From 8e06c427407d51be9ad111c13c55cfc5932f2529 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 28 Feb 2020 14:32:11 +0300 Subject: [PATCH 01/30] Files: added new interface --- .../Server/Controllers/FilesController.cs | 18 ++ .../Server/Core/Dao/Interfaces/IFileDao.cs | 262 ++++++++++++++++++ .../Server/Core/Dao/TeamlabDao/FileDao.cs | 226 ++++++++++++++- .../ASC.Files/Server/Core/Entries/File.cs | 10 + .../Server/Core/FileStorageService.cs | 24 ++ 5 files changed, 539 insertions(+), 1 deletion(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index ddf13b45ca..7e3926e73c 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -279,7 +279,12 @@ namespace ASC.Api.Documents public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType) { return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); + } + [Read("{folderId:int}", order: int.MaxValue)] + public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType) + { + return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); } /// @@ -822,6 +827,19 @@ namespace ASC.Api.Documents return FileWrapperHelper.Get(file); } + /// + /// Returns a detailed information about the file with the ID specified in the request + /// + /// File information + /// Files + /// File info + [Read("file/{fileId:int}")] + public FileWrapper GetFileInfo(int fileId, int version = -1) + { + var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); + return FileWrapperHelper.Get(file); + } + /// /// Updates the information of the selected file with the parameters specified in the request /// diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs index c2f3df23d1..64e4a69f8d 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs @@ -32,6 +32,268 @@ using ASC.Web.Files.Services.DocumentService; namespace ASC.Files.Core { + public interface IFileDao + { + /// + /// Clear the application cache for the specific file + /// + void InvalidateCache(T fileId); + + /// + /// Receive file + /// + /// file id + /// + File GetFile(T fileId); + + /// + /// Receive file + /// + /// file id + /// file version + /// + File GetFile(T fileId, int fileVersion); + + /// + /// Receive file + /// + /// folder id + /// file name + /// + /// file + /// + File GetFile(T parentId, string title); + + /// + /// Receive last file without forcesave + /// + /// file id + /// + /// + File GetFileStable(T fileId, int fileVersion = -1); + + /// + /// Returns all versions of the file + /// + /// + /// + List> GetFileHistory(T fileId); + + /// + /// Gets the file (s) by ID (s) + /// + /// id file + /// + List> GetFiles(T[] fileIds); + + /// + /// Gets the file (s) by ID (s) for share + /// + /// id file + /// + /// + /// + /// + /// + /// + List> GetFilesForShare(T[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent); + + /// + /// + /// + /// + /// + List GetFiles(T parentId); + + /// + /// Get files in folder + /// + /// folder id + /// + /// filterType type + /// + /// + /// + /// + /// + /// list of files + /// + /// Return only the latest versions of files of a folder + /// + List> GetFiles(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false); + + /// + /// Get stream of file + /// + /// + /// Stream + Stream GetFileStream(File file); + + /// + /// Get stream of file + /// + /// + /// + /// Stream + Stream GetFileStream(File file, long offset); + + /// + /// Get presigned uri + /// + /// + /// + /// Stream uri + Uri GetPreSignedUri(File file, TimeSpan expires); + + /// + /// Check is supported PreSignedUri + /// + /// + /// Stream uri + bool IsSupportedPreSignedUri(File file); + + /// + /// Saves / updates the version of the file + /// and save stream of file + /// + /// + /// + /// + /// + /// Updates the file if: + /// - The file comes with the given id + /// - The file with that name in the folder / container exists + /// + /// Save in all other cases + /// + File SaveFile(File file, Stream fileStream); + + /// + /// + /// + /// + /// + /// + File ReplaceFileVersion(File file, Stream fileStream); + + /// + /// Deletes a file including all previous versions + /// + /// file id + void DeleteFile(T fileId); + + /// + /// Checks whether or not file + /// + /// file name + /// folder id + /// Returns true if the file exists, otherwise false + bool IsExist(string title, T folderId); + + /// + /// Moves a file or set of files in a folder + /// + /// file id + /// The ID of the destination folder + object MoveFile(T fileId, T toFolderId); + + /// + /// Copy the files in a folder + /// + /// file id + /// The ID of the destination folder + File CopyFile(T fileId, T toFolderId); + + /// + /// Rename file + /// + /// + /// new name + object FileRename(File file, string newTitle); + + /// + /// Update comment file + /// + /// file id + /// file version + /// new comment + string UpdateComment(T fileId, int fileVersion, string comment); + + /// + /// Complete file version + /// + /// file id + /// file version + void CompleteVersion(T fileId, int fileVersion); + + /// + /// Continue file version + /// + /// file id + /// file version + void ContinueVersion(T fileId, int fileVersion); + + /// + /// Check the need to use the trash before removing + /// + /// + /// + bool UseTrashForRemove(File file); + + #region chunking + + ChunkedUploadSession CreateUploadSession(File file, long contentLength); + + #endregion + + #region Only in TMFileDao + + /// + /// Set created by + /// + /// + /// + void ReassignFiles(T[] fileIds, Guid newOwnerId); + + /// + /// Search files in SharedWithMe & Projects + /// + /// + /// + /// + /// + /// + /// + /// + List> GetFiles(T[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent); + + /// + /// Search the list of files containing text + /// Only in TMFileDao + /// + /// search text + /// + /// list of files + IEnumerable> Search(string text, bool bunch = false); + + /// + /// Checks whether file exists on storage + /// + /// file + /// + bool IsExistOnStorage(File file); + + void SaveEditHistory(File file, string changes, Stream differenceStream); + + List GetEditHistory(DocumentServiceHelper documentServiceHelper, T fileId, int fileVersion = 0); + + Stream GetDifferenceStream(File file); + + bool ContainChanges(T fileId, int fileVersion); + + #endregion + } + /// /// Interface encapsulates access toFolderId files /// diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index 4c25de1fe4..b1a70ee87e 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -51,7 +51,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Core.Data { - public class FileDao : AbstractDao, IFileDao + public class FileDao : AbstractDao, IFileDao, IFileDao { private static readonly object syncRoot = new object(); public FactoryIndexer FactoryIndexer { get; } @@ -106,12 +106,22 @@ namespace ASC.Files.Core.Data { } + public void InvalidateCache(int fileId) + { + } + public File GetFile(object fileId) { var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString() && r.CurrentVersion); return FromQueryWithShared(query).SingleOrDefault(); } + public File GetFile(int fileId) + { + var query = GetFileQuery(r => r.Id == fileId && r.CurrentVersion); + return FromQueryWithSharedInt(query).SingleOrDefault(); + } + public File GetFile(object fileId, int fileVersion) { var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString() && r.Version == fileVersion); @@ -1200,6 +1210,31 @@ namespace ASC.Files.Core.Data .ToList(); } + protected List> FromQueryWithSharedInt(IQueryable dbFiles) + { + return dbFiles + .Select(r => new DbFileQuery + { + file = r, + root = + FilesDbContext.Folders + .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) + .Where(x => x.folder.TenantId == r.TenantId) + .Where(x => x.tree.FolderId == r.FolderId) + .OrderByDescending(r => r.tree.Level) + .Select(r => r.folder) + .FirstOrDefault(), + shared = + FilesDbContext.Security + .Where(x => x.EntryType == FileEntryType.File) + .Where(x => x.EntryId == r.Id.ToString()) + .Any() + }) + .ToList() + .Select(ToFileInt) + .ToList(); + } + protected List FromQuery(IQueryable dbFiles) { return dbFiles @@ -1243,6 +1278,193 @@ namespace ASC.Files.Core.Data file.Forcesave = r.file.Forcesave; return file; } + + public File ToFileInt(DbFileQuery r) + { + var file = ServiceProvider.GetService>(); + file.ID = r.file.Id; + file.Title = r.file.Title; + file.FolderID = r.file.FolderId; + file.CreateOn = TenantUtil.DateTimeFromUtc(r.file.CreateOn); + file.CreateBy = r.file.CreateBy; + file.Version = r.file.Version; + file.VersionGroup = r.file.VersionGroup; + file.ContentLength = r.file.ContentLength; + file.ModifiedOn = TenantUtil.DateTimeFromUtc(r.file.ModifiedOn); + file.ModifiedBy = r.file.ModifiedBy; + file.RootFolderType = r.root?.FolderType ?? default; + file.RootFolderCreator = r.root?.CreateBy ?? default; + file.RootFolderId = r.root?.Id ?? default; + file.Shared = r.shared; + file.ConvertedType = r.file.ConvertedType; + file.Comment = r.file.Comment; + file.Encrypted = r.file.Encrypted; + file.Forcesave = r.file.Forcesave; + return file; + } + + + ///test:test + + public File GetFile(int fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public File GetFile(int parentId, string title) + { + throw new NotImplementedException(); + } + + public File GetFileStable(int fileId, int fileVersion = -1) + { + throw new NotImplementedException(); + } + + public List> GetFileHistory(int fileId) + { + throw new NotImplementedException(); + } + + public List> GetFiles(int[] fileIds) + { + throw new NotImplementedException(); + } + + public List> GetFilesForShare(int[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + throw new NotImplementedException(); + } + + public List GetFiles(int parentId) + { + throw new NotImplementedException(); + } + + public List> GetFiles(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + throw new NotImplementedException(); + } + + public Stream GetFileStream(File file) + { + throw new NotImplementedException(); + } + + public Stream GetFileStream(File file, long offset) + { + throw new NotImplementedException(); + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotImplementedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + throw new NotImplementedException(); + } + + public File SaveFile(File file, Stream fileStream) + { + throw new NotImplementedException(); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + throw new NotImplementedException(); + } + + public void DeleteFile(int fileId) + { + throw new NotImplementedException(); + } + + public bool IsExist(string title, int folderId) + { + throw new NotImplementedException(); + } + + public object MoveFile(int fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + public File CopyFile(int fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + public object FileRename(File file, string newTitle) + { + throw new NotImplementedException(); + } + + public string UpdateComment(int fileId, int fileVersion, string comment) + { + throw new NotImplementedException(); + } + + public void CompleteVersion(int fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public void ContinueVersion(int fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public bool UseTrashForRemove(File file) + { + throw new NotImplementedException(); + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + throw new NotImplementedException(); + } + + public void ReassignFiles(int[] fileIds, Guid newOwnerId) + { + throw new NotImplementedException(); + } + + public List> GetFiles(int[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + throw new NotImplementedException(); + } + + IEnumerable> IFileDao.Search(string text, bool bunch) + { + throw new NotImplementedException(); + } + + public bool IsExistOnStorage(File file) + { + throw new NotImplementedException(); + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + throw new NotImplementedException(); + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, int fileId, int fileVersion = 0) + { + throw new NotImplementedException(); + } + + public Stream GetDifferenceStream(File file) + { + throw new NotImplementedException(); + } + + public bool ContainChanges(int fileId, int fileVersion) + { + throw new NotImplementedException(); + } } public class DbFileQuery @@ -1257,7 +1479,9 @@ namespace ASC.Files.Core.Data public static DIHelper AddFileDaoService(this DIHelper services) { services.TryAddScoped(); + services.TryAddScoped, FileDao>(); services.TryAddTransient(); + services.TryAddTransient>(); return services .AddFilesDbContextService() diff --git a/products/ASC.Files/Server/Core/Entries/File.cs b/products/ASC.Files/Server/Core/Entries/File.cs index 7d82694d14..6bcc24afd6 100644 --- a/products/ASC.Files/Server/Core/Entries/File.cs +++ b/products/ASC.Files/Server/Core/Entries/File.cs @@ -54,6 +54,16 @@ namespace ASC.Files.Core [EnumMember] IsEditingAlone = 0x10 } + public class File : File + { + [DataMember(Name = "id")] + public new T ID { get; set; } + + public File(Global global, FilesLinkUtility filesLinkUtility, FileUtility fileUtility, FileConverter fileConverter) : base(global, filesLinkUtility, fileUtility, fileConverter) + { + } + } + [Serializable] [DataContract(Name = "file", Namespace = "")] [DebuggerDisplay("{Title} ({ID} v{Version})")] diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index b42f992c1d..7ba1562192 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -445,6 +445,30 @@ namespace ASC.Web.Files.Services.WCFService return file; } + public File GetFile(int fileId, int version) + { + var fileDao = GetFileDao() as IFileDao; + fileDao.InvalidateCache(fileId); + + var file = version > 0 + ? fileDao.GetFile(fileId, version) + : fileDao.GetFile(fileId); + ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + + EntryManager.SetFileStatus(file); + + if (file.RootFolderType == FolderType.USER + && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) + { + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + } + + return file; + } + public ItemList GetSiblingsFile(string fileId, string parentId, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); From aa9577e5c03972207743e46070bf1ffa72259260 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Mon, 2 Mar 2020 15:31:53 +0300 Subject: [PATCH 02/30] Files: template methods --- .../Server/Controllers/FilesController.cs | 32 +- .../Server/Core/Dao/Interfaces/IDaoFactory.cs | 4 + .../Server/Core/Dao/Interfaces/IFileDao.cs | 22 +- .../Server/Core/Dao/Interfaces/IFolderDao.cs | 253 +++++++++ .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 18 +- .../Server/Core/Dao/TeamlabDao/FileDao.cs | 532 ++++++++---------- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 296 +++++++--- .../Core/Entries/ChunkedUploadSession.cs | 14 +- .../ASC.Files/Server/Core/Entries/File.cs | 30 + .../Server/Core/Entries/FileEntry.cs | 18 +- .../ASC.Files/Server/Core/Entries/Folder.cs | 40 ++ .../Server/Core/FileStorageService.cs | 308 +++++----- .../Server/Core/Security/FileSecurity.cs | 10 + products/ASC.Files/Server/Helpers/Global.cs | 140 +++++ .../HttpHandlers/ChunkedUploaderHandler.cs | 6 +- .../Server/HttpHandlers/FileHandler.ashx.cs | 20 +- .../FileOperations/FileDeleteOperation.cs | 24 +- .../FileOperations/FileDownloadOperation.cs | 66 ++- .../FileOperations/FileMarkAsReadOperation.cs | 12 +- .../FileOperations/FileMoveCopyOperation.cs | 31 +- .../FileOperations/FileOperation.cs | 32 +- .../FileOperations/FileOperationsManager.cs | 26 +- .../WCFService/IFileStorageService.cs | 2 +- .../Utils/ChunkedUploadSessionHolder.cs | 24 +- .../ASC.Files/Server/Utils/EntryManager.cs | 309 +++++++++- .../ASC.Files/Server/Utils/FileConverter.cs | 2 +- .../ASC.Files/Server/Utils/FileShareLink.cs | 27 + .../ASC.Files/Server/Utils/FileTracker.cs | 25 + .../ASC.Files/Server/Utils/FileUploader.cs | 26 +- 29 files changed, 1643 insertions(+), 706 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 7e3926e73c..acab8fc9dc 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -767,7 +767,7 @@ namespace ASC.Api.Documents [Create("{folderId}/file")] public FileWrapper CreateFile(string folderId, string title) { - var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); + var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); return FileWrapperHelper.Get(file); } @@ -907,7 +907,7 @@ namespace ASC.Api.Documents [Read("file/{fileId}/checkconversion")] public IEnumerable CheckConversion(string fileId, bool start) { - return FileStorageService.CheckConversion(new ItemList> + return FileStorageService.CheckConversion(new ItemList> { new ItemList { fileId, "0", start.ToString() } }) @@ -971,7 +971,7 @@ namespace ASC.Api.Documents var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); - var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); + var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); return entries.Select(x => FileWrapperHelper.Get((Files.Core.File)x)); } @@ -994,7 +994,7 @@ namespace ASC.Api.Documents itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); } /// @@ -1016,7 +1016,7 @@ namespace ASC.Api.Documents itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); } /// @@ -1033,7 +1033,7 @@ namespace ASC.Api.Documents itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); } /// @@ -1111,7 +1111,7 @@ namespace ASC.Api.Documents itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); + return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); } /// @@ -1123,7 +1123,7 @@ namespace ASC.Api.Documents [Update("fileops/emptytrash")] public IEnumerable EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } /// @@ -1208,7 +1208,7 @@ namespace ASC.Api.Documents Aces = list, Message = sharingMessage }; - FileStorageService.SetAceObject(aceCollection, notify); + FileStorageService.SetAceObject(aceCollection, notify); } return GetFileSecurityInfo(fileId); } @@ -1238,7 +1238,7 @@ namespace ASC.Api.Documents Aces = list, Message = sharingMessage }; - FileStorageService.SetAceObject(aceCollection, notify); + FileStorageService.SetAceObject(aceCollection, notify); } return GetFolderSecurityInfo(folderId); @@ -1260,7 +1260,7 @@ namespace ASC.Api.Documents itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - FileStorageService.RemoveAce(itemList); + FileStorageService.RemoveAce(itemList); return true; } @@ -1298,7 +1298,7 @@ namespace ASC.Api.Documents Entries = new ItemList { objectId }, Aces = list }; - FileStorageService.SetAceObject(aceCollection, false); + FileStorageService.SetAceObject(aceCollection, false); sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); } @@ -1548,11 +1548,13 @@ namespace ASC.Api.Documents private FolderContentWrapper ToFolderContentWrapper(object folderId, Guid userIdOrGroupId, FilterType filterType) { - SortedByType sortBy; - if (!Enum.TryParse(ApiContext.SortBy, true, out sortBy)) + if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) + { sortBy = SortedByType.AZ; + } + var startIndex = Convert.ToInt32(ApiContext.StartIndex); - return FolderContentWrapperHelper.Get(FileStorageService.GetFolderItems(folderId.ToString(), + return FolderContentWrapperHelper.Get(FileStorageService.GetFolderItems(folderId.ToString(), startIndex, Convert.ToInt32(ApiContext.Count) - 1, //NOTE: in ApiContext +1 filterType, diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs index 35ad8670d7..e55c58592e 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs @@ -32,8 +32,12 @@ namespace ASC.Files.Core { IFolderDao FolderDao { get; } + IFolderDao GetFolderDao(); + IFileDao FileDao { get; } + IFileDao GetFileDao(); + ITagDao TagDao { get; } ISecurityDao SecurityDao { get; } diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs index 64e4a69f8d..e314a214ec 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs @@ -103,7 +103,7 @@ namespace ASC.Files.Core /// /// /// - List GetFiles(T parentId); + List GetFiles(T parentId); /// /// Get files in folder @@ -188,14 +188,14 @@ namespace ASC.Files.Core /// file name /// folder id /// Returns true if the file exists, otherwise false - bool IsExist(string title, T folderId); + bool IsExist(string title, object folderId); /// /// Moves a file or set of files in a folder /// /// file id /// The ID of the destination folder - object MoveFile(T fileId, T toFolderId); + T MoveFile(T fileId, T toFolderId); /// /// Copy the files in a folder @@ -209,7 +209,7 @@ namespace ASC.Files.Core /// /// /// new name - object FileRename(File file, string newTitle); + T FileRename(File file, string newTitle); /// /// Update comment file @@ -240,9 +240,15 @@ namespace ASC.Files.Core /// bool UseTrashForRemove(File file); + string GetUniqFilePath(File file, string fileTitle); + #region chunking - ChunkedUploadSession CreateUploadSession(File file, long contentLength); + ChunkedUploadSession CreateUploadSession(File file, long contentLength); + + void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength); + + void AbortUploadSession(ChunkedUploadSession uploadSession); #endregion @@ -507,11 +513,11 @@ namespace ASC.Files.Core #region chunking - ChunkedUploadSession CreateUploadSession(File file, long contentLength); + ChunkedUploadSession CreateUploadSession(File file, long contentLength); - void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength); + void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength); - void AbortUploadSession(ChunkedUploadSession uploadSession); + void AbortUploadSession(ChunkedUploadSession uploadSession); #endregion diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs index 106bd0414b..0e9b00cf96 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs @@ -30,6 +30,259 @@ using System.Threading; namespace ASC.Files.Core { + public interface IFolderDao + { + /// + /// Get folder by id. + /// + /// folder id + /// folder + Folder GetFolder(T folderId); + + /// + /// Returns the folder with the given name and id of the root + /// + /// + /// + /// + Folder GetFolder(string title, T parentId); + + /// + /// Gets the root folder + /// + /// folder id + /// root folder + Folder GetRootFolder(T folderId); + + /// + /// Gets the root folder + /// + /// file id + /// root folder + Folder GetRootFolderByFile(T fileId); + + /// + /// Get a list of folders in current folder. + /// + /// + List> GetFolders(T parentId); + + /// + /// Get a list of folders. + /// + /// + /// + /// + /// + /// + /// + /// + /// + List> GetFolders(T parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false); + + /// + /// Gets the folder (s) by ID (s) + /// + /// + /// + /// + /// + /// + /// + /// + /// + List> GetFolders(T[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true); + + /// + /// Get folder, contains folder with id + /// + /// folder id + /// + List> GetParentFolders(T folderId); + + /// + /// save or update folder + /// + /// + /// + T SaveFolder(Folder folder); + + /// + /// delete folder + /// + /// folder id + void DeleteFolder(T folderId); + + /// + /// move folder + /// + /// folder id + /// destination folder id + /// + T MoveFolder(T folderId, T toFolderId, CancellationToken? cancellationToken); + + /// + /// copy folder + /// + /// + /// + /// + /// + /// + Folder CopyFolder(T folderId, T toFolderId, CancellationToken? cancellationToken); + + /// + /// Validate the transfer operation directory to another directory. + /// + /// + /// + /// + /// Returns pair of file ID, file name, in which the same name. + /// + IDictionary CanMoveOrCopy(T[] folderIds, T to); + + /// + /// Rename folder + /// + /// + /// new name + T RenameFolder(Folder folder, string newTitle); + + /// + /// Gets the number of files and folders to the container in your + /// + /// folder id + /// + int GetItemsCount(T folderId); + + /// + /// Check folder on emptiness + /// + /// folder id + /// + bool IsEmpty(T folderId); + + /// + /// Check the need to use the trash before removing + /// + /// + /// + bool UseTrashForRemove(Folder folder); + + /// + /// Check the need to use recursion for operations + /// + /// + /// + /// + bool UseRecursiveOperation(T folderId, T toRootFolderId); + + /// + /// Check the possibility to calculate the number of subitems + /// + /// + /// + bool CanCalculateSubitems(T entryId); + + /// + /// Returns maximum size of file which can be uploaded to specific folder + /// + /// Id of the folder + /// Determines whenever supposed upload will be chunked (true) or not (false) + /// Maximum size of file which can be uploaded to folder + long GetMaxUploadSize(T folderId, bool chunkedUpload = false); + + #region Only for TMFolderDao + + /// + /// Set created by + /// + /// + /// + void ReassignFolders(T[] folderIds, Guid newOwnerId); + + /// + /// Search the list of folders containing text in title + /// Only in TMFolderDao + /// + /// + /// + /// + IEnumerable> Search(string text, bool bunch = false); + + /// + /// Only in TMFolderDao + /// + /// + /// + /// + /// + /// + T GetFolderID(string module, string bunch, Guid data, bool createIfNotExists); + + IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists); + + /// + /// Returns id folder "Shared Documents" + /// Only in TMFolderDao + /// + /// + T GetFolderIDCommon(bool createIfNotExists); + + /// + /// Returns id folder "My Documents" + /// Only in TMFolderDao + /// + /// + /// + /// + T GetFolderIDUser(bool createIfNotExists, Guid? userId = null); + + /// + /// Returns id folder "Shared with me" + /// Only in TMFolderDao + /// + /// + /// + T GetFolderIDShare(bool createIfNotExists); + + /// + /// Returns id folder "Trash" + /// Only in TMFolderDao + /// + /// + /// + /// + T GetFolderIDTrash(bool createIfNotExists, Guid? userId = null); + + /// + /// Returns id folder "Projects" + /// Only in TMFolderDao + /// + /// + /// + T GetFolderIDProjects(bool createIfNotExists); + + + /// + /// Return id of related object + /// Only in TMFolderDao + /// + /// + /// + string GetBunchObjectID(T folderID); + + /// + /// Return ids of related objects + /// Only in TMFolderDao + /// + /// + /// + Dictionary GetBunchObjectIDs(List folderIDs); + + #endregion + } + public interface IFolderDao { /// diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index 561c729d5b..ee540574c4 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -24,26 +24,42 @@ */ +using System; + using ASC.Common; using ASC.Files.Core.Security; +using Microsoft.Extensions.DependencyInjection; + namespace ASC.Files.Core.Data { public class DaoFactory : IDaoFactory { + public IServiceProvider ServiceProvider { get; } public IFileDao FileDao { get; } public IFolderDao FolderDao { get; } public ITagDao TagDao { get; } public ISecurityDao SecurityDao { get; } public IProviderDao ProviderDao { get; } - public DaoFactory(IFileDao fileDao, IFolderDao folderDao, ITagDao tagDao, ISecurityDao securityDao) + public DaoFactory(IServiceProvider serviceProvider, IFileDao fileDao, IFolderDao folderDao, ITagDao tagDao, ISecurityDao securityDao) { + ServiceProvider = serviceProvider; FileDao = fileDao; FolderDao = folderDao; TagDao = tagDao; SecurityDao = securityDao; } + + public IFileDao GetFileDao() + { + return ServiceProvider.GetService>(); + } + + public IFolderDao GetFolderDao() + { + return ServiceProvider.GetService>(); + } } public static class DaoFactoryExtention diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index b1a70ee87e..7c74085ff9 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -104,6 +104,7 @@ namespace ASC.Files.Core.Data public void InvalidateCache(object fileId) { + throw new NotImplementedException(); } public void InvalidateCache(int fileId) @@ -112,27 +113,36 @@ namespace ASC.Files.Core.Data public File GetFile(object fileId) { - var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString() && r.CurrentVersion); - return FromQueryWithShared(query).SingleOrDefault(); + throw new NotImplementedException(); } public File GetFile(int fileId) { var query = GetFileQuery(r => r.Id == fileId && r.CurrentVersion); - return FromQueryWithSharedInt(query).SingleOrDefault(); + return FromQueryWithShared(query).SingleOrDefault(); } public File GetFile(object fileId, int fileVersion) { - var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString() && r.Version == fileVersion); + throw new NotImplementedException(); + } + + public File GetFile(int fileId, int fileVersion) + { + var query = GetFileQuery(r => r.Id == fileId && r.Version == fileVersion); return FromQueryWithShared(query).SingleOrDefault(); } public File GetFile(object parentId, string title) + { + throw new NotImplementedException(); + } + + public File GetFile(int parentId, string title) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(title); - var query = GetFileQuery(r => r.Title == title && r.CurrentVersion == true && r.FolderId.ToString() == parentId.ToString()) + var query = GetFileQuery(r => r.Title == title && r.CurrentVersion == true && r.FolderId == parentId) .OrderBy(r => r.CreateOn); return FromQueryWithShared(query).FirstOrDefault(); @@ -140,7 +150,12 @@ namespace ASC.Files.Core.Data public File GetFileStable(object fileId, int fileVersion = -1) { - var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString() && r.Forcesave == ForcesaveType.None); + throw new NotImplementedException(); + } + + public File GetFileStable(int fileId, int fileVersion = -1) + { + var query = GetFileQuery(r => r.Id == fileId && r.Forcesave == ForcesaveType.None); if (fileVersion >= 0) { @@ -154,26 +169,40 @@ namespace ASC.Files.Core.Data public List GetFileHistory(object fileId) { - var query = GetFileQuery(r => r.Id.ToString() == fileId.ToString()).OrderByDescending(r => r.Version); + throw new NotImplementedException(); + } + + public List> GetFileHistory(int fileId) + { + var query = GetFileQuery(r => r.Id == fileId).OrderByDescending(r => r.Version); return FromQueryWithShared(query); } public List GetFiles(object[] fileIds) { - if (fileIds == null || fileIds.Length == 0) return new List(); + throw new NotImplementedException(); + } - var query = GetFileQuery(r => fileIds.Any(a => a.ToString() == r.Id.ToString()) && r.CurrentVersion); + public List> GetFiles(int[] fileIds) + { + if (fileIds == null || fileIds.Length == 0) return new List>(); + + var query = GetFileQuery(r => fileIds.Any(a => a == r.Id) && r.CurrentVersion); return FromQueryWithShared(query); } public List GetFilesForShare(object[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) { - if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List(); + throw new NotImplementedException(); + } - var fileIdsStrings = fileIds.Select(r => r.ToString()).ToList(); - var query = GetFileQuery(r => fileIdsStrings.Any(a => a == r.Id.ToString()) && r.CurrentVersion); + public List> GetFilesForShare(int[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var query = GetFileQuery(r => fileIds.Any(a => a == r.Id) && r.CurrentVersion); if (!string.IsNullOrEmpty(searchText)) { @@ -223,33 +252,41 @@ namespace ASC.Files.Core.Data return FromQuery(query); } + public List GetFiles(object parentId) { - var parentIdString = parentId.ToString(); - var query = GetFileQuery(r => r.FolderId.ToString() == parentIdString && r.CurrentVersion).Select(r => r.Id); + throw new NotImplementedException(); + } + + public List GetFiles(int parentId) + { + var query = GetFileQuery(r => r.FolderId == parentId && r.CurrentVersion).Select(r => r.Id); return Query(FilesDbContext.Files) - .Where(r => r.FolderId.ToString() == parentIdString && r.CurrentVersion) + .Where(r => r.FolderId == parentId && r.CurrentVersion) .Select(r => r.Id) - .ToList() - .ConvertAll(r => (object)r); + .ToList(); } public List GetFiles(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) { - if (filterType == FilterType.FoldersOnly) return new List(); + throw new NotImplementedException(); + } + + public List> GetFiles(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); - var parentIdString = parentId.ToString(); - var q = GetFileQuery(r => r.FolderId.ToString() == parentIdString && r.CurrentVersion); + var q = GetFileQuery(r => r.FolderId == parentId && r.CurrentVersion); if (withSubfolders) { q = GetFileQuery(r => r.CurrentVersion) .Join(FilesDbContext.Tree, r => r.FolderId, a => a.FolderId, (file, tree) => new { file, tree }) - .Where(r => r.tree.ParentId.ToString() == parentIdString) + .Where(r => r.tree.ParentId == parentId) .Select(r => r.file); } @@ -326,11 +363,21 @@ namespace ASC.Files.Core.Data } public Stream GetFileStream(File file, long offset) + { + throw new NotImplementedException(); + } + + public Stream GetFileStream(File file, long offset) { return GlobalStore.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file), (int)offset); } public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotImplementedException(); + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) { return GlobalStore.GetStore().GetPreSignedUri(string.Empty, GetUniqFilePath(file), expires, new List @@ -340,16 +387,31 @@ namespace ASC.Files.Core.Data } public bool IsSupportedPreSignedUri(File file) + { + throw new NotImplementedException(); + } + + public bool IsSupportedPreSignedUri(File file) { return GlobalStore.GetStore().IsSupportedPreSignedUri; } public Stream GetFileStream(File file) + { + throw new NotImplementedException(); + } + + public Stream GetFileStream(File file) { return GetFileStream(file, 0); } public File SaveFile(File file, Stream fileStream) + { + throw new NotImplementedException(); + } + + public File SaveFile(File file, Stream fileStream) { if (file == null) { @@ -365,7 +427,7 @@ namespace ASC.Files.Core.Data if (CoreBaseSettings.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace")) { var personalMaxSpace = CoreConfiguration.PersonalMaxSpace(SettingsManager); - if (personalMaxSpace - GlobalSpace.GetUserUsedSpace(file.ID == null ? AuthContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength) + if (personalMaxSpace - GlobalSpace.GetUserUsedSpace(file.ID == default ? AuthContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength) { throw FileSizeComment.GetPersonalFreeSpaceException(personalMaxSpace); } @@ -377,7 +439,7 @@ namespace ASC.Files.Core.Data { using var tx = FilesDbContext.Database.BeginTransaction(); - if (file.ID == null) + if (file.ID == default) { file.ID = FilesDbContext.Files.Max(r => r.Id) + 1; file.Version = 1; @@ -395,7 +457,7 @@ namespace ASC.Files.Core.Data if (file.CreateOn == default) file.CreateOn = TenantUtil.DateTimeNow(); var toUpdate = FilesDbContext.Files - .Where(r => r.Id.ToString() == file.ID.ToString() && r.CurrentVersion && r.TenantId == TenantID) + .Where(r => r.Id == file.ID && r.CurrentVersion && r.TenantId == TenantID) .FirstOrDefault(); if (toUpdate != null) @@ -406,7 +468,7 @@ namespace ASC.Files.Core.Data var toInsert = new DbFile { - Id = (int)file.ID, + Id = file.ID, Version = file.Version, VersionGroup = file.VersionGroup, CurrentVersion = true, @@ -486,9 +548,14 @@ namespace ASC.Files.Core.Data } public File ReplaceFileVersion(File file, Stream fileStream) + { + throw new NotImplementedException(); + } + + public File ReplaceFileVersion(File file, Stream fileStream) { if (file == null) throw new ArgumentNullException("file"); - if (file.ID == null) throw new ArgumentException("No file id or folder id toFolderId determine provider"); + if (file.ID == default) throw new ArgumentException("No file id or folder id toFolderId determine provider"); var maxChunkedUploadSize = SetupInfo.MaxChunkedUploadSize(TenantExtra, TenantStatisticProvider); @@ -500,7 +567,7 @@ namespace ASC.Files.Core.Data if (CoreBaseSettings.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace")) { var personalMaxSpace = CoreConfiguration.PersonalMaxSpace(SettingsManager); - if (personalMaxSpace - GlobalSpace.GetUserUsedSpace(file.ID == null ? AuthContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength) + if (personalMaxSpace - GlobalSpace.GetUserUsedSpace(file.ID == default ? AuthContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength) { throw FileSizeComment.GetPersonalFreeSpaceException(personalMaxSpace); } @@ -521,7 +588,7 @@ namespace ASC.Files.Core.Data if (file.CreateOn == default) file.CreateOn = TenantUtil.DateTimeNow(); var toUpdate = FilesDbContext.Files - .Where(r => r.Id.ToString() == file.ID.ToString() && r.Version == file.Version) + .Where(r => r.Id == file.ID && r.Version == file.Version) .FirstOrDefault(); toUpdate.Version = file.Version; @@ -588,14 +655,14 @@ namespace ASC.Files.Core.Data return GetFile(file.ID); } - private void DeleteVersion(File file) + private void DeleteVersion(File file) { if (file == null - || file.ID == null + || file.ID == default || file.Version <= 1) return; var toDelete = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)file.ID) + .Where(r => r.Id == file.ID) .Where(r => r.Version == file.Version) .FirstOrDefault(); @@ -606,7 +673,7 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)file.ID) + .Where(r => r.Id == file.ID) .Where(r => r.Version == file.Version - 1) .FirstOrDefault(); @@ -614,29 +681,34 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); } - private void DeleteVersionStream(File file) + private void DeleteVersionStream(File file) { GlobalStore.GetStore().DeleteDirectory(GetUniqFileVersionPath(file.ID, file.Version)); } - private void SaveFileStream(File file, Stream stream) + private void SaveFileStream(File file, Stream stream) { GlobalStore.GetStore().Save(string.Empty, GetUniqFilePath(file), stream, file.Title); } public void DeleteFile(object fileId) + { + throw new NotImplementedException(); + } + + public void DeleteFile(int fileId) { DeleteFile(fileId, true); } - private void DeleteFile(object fileId, bool deleteFolder) + private void DeleteFile(int fileId, bool deleteFolder) { - if (fileId == null) return; + if (fileId == default) return; using var tx = FilesDbContext.Database.BeginTransaction(); - var fromFolders = Query(FilesDbContext.Files).Where(r => r.Id == (int)fileId).GroupBy(r => r.Id).SelectMany(r => r.Select(a => a.FolderId)).Distinct().ToList(); + var fromFolders = Query(FilesDbContext.Files).Where(r => r.Id == fileId).GroupBy(r => r.Id).SelectMany(r => r.Select(a => a.FolderId)).Distinct().ToList(); - var toDeleteFiles = Query(FilesDbContext.Files).Where(r => r.Id == (int)fileId); + var toDeleteFiles = Query(FilesDbContext.Files).Where(r => r.Id == fileId); FilesDbContext.RemoveRange(toDeleteFiles); var toDeleteLinks = Query(FilesDbContext.TagLink).Where(r => r.EntryId == fileId.ToString()).Where(r => r.EntryType == FileEntryType.File); @@ -667,33 +739,43 @@ namespace ASC.Files.Core.Data } public bool IsExist(string title, object folderId) + { + throw new NotImplementedException(); + } + + public bool IsExist(string title, int folderId) { return Query(FilesDbContext.Files) .Where(r => r.Title == title) - .Where(r => r.FolderId == (int)folderId) + .Where(r => r.FolderId == folderId) .Where(r => r.CurrentVersion) .Any(); } public object MoveFile(object fileId, object toFolderId) { - if (fileId == null) return null; + throw new NotImplementedException(); + } + + public int MoveFile(int fileId, int toFolderId) + { + if (fileId == default) return default; using (var tx = FilesDbContext.Database.BeginTransaction()) { var fromFolders = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .GroupBy(r => r.Id) .SelectMany(r => r.Select(a => a.FolderId)) .Distinct() .ToList(); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId); + .Where(r => r.Id == fileId); foreach (var f in toUpdate) { - f.FolderId = (int)toFolderId; + f.FolderId = toFolderId; if (GlobalFolder.GetFolderTrash(FolderDao).Equals(toFolderId)) { @@ -717,7 +799,7 @@ namespace ASC.Files.Core.Data .ToList(); var wrapper = ServiceProvider.GetService(); - wrapper.Id = (int)fileId; + wrapper.Id = fileId; wrapper.Folders = parentFoldersIds.Select(r => new FilesFoldersWrapper() { FolderId = r.ToString() }).ToList(); FactoryIndexer.Update(wrapper, @@ -728,11 +810,16 @@ namespace ASC.Files.Core.Data } public File CopyFile(object fileId, object toFolderId) + { + throw new NotImplementedException(); + } + + public File CopyFile(int fileId, int toFolderId) { var file = GetFile(fileId); if (file != null) { - var copy = ServiceProvider.GetService(); + var copy = ServiceProvider.GetService>(); copy.FileStatus = file.FileStatus; copy.FolderID = toFolderId; copy.Title = file.Title; @@ -752,10 +839,15 @@ namespace ASC.Files.Core.Data } public object FileRename(File file, string newTitle) + { + throw new NotImplementedException(); + } + + public int FileRename(File file, string newTitle) { newTitle = Global.ReplaceInvalidCharsAndTruncate(newTitle); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)file.ID) + .Where(r => r.Id == file.ID) .Where(r => r.CurrentVersion) .FirstOrDefault(); @@ -769,12 +861,17 @@ namespace ASC.Files.Core.Data } public string UpdateComment(object fileId, int fileVersion, string comment) + { + throw new NotImplementedException(); + } + + public string UpdateComment(int fileId, int fileVersion, string comment) { comment ??= string.Empty; comment = comment.Substring(0, Math.Min(comment.Length, 255)); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Version == fileVersion) .FirstOrDefault(); @@ -786,9 +883,14 @@ namespace ASC.Files.Core.Data } public void CompleteVersion(object fileId, int fileVersion) + { + + } + + public void CompleteVersion(int fileId, int fileVersion) { var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Version >= fileVersion); foreach (var f in toUpdate) @@ -800,17 +902,22 @@ namespace ASC.Files.Core.Data } public void ContinueVersion(object fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public void ContinueVersion(int fileId, int fileVersion) { using var tx = FilesDbContext.Database.BeginTransaction(); var versionGroup = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Version == fileVersion) .Select(r => r.VersionGroup) .FirstOrDefault(); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Version >= fileVersion) .Where(r => r.VersionGroup >= versionGroup); @@ -825,35 +932,39 @@ namespace ASC.Files.Core.Data } public bool UseTrashForRemove(File file) + { + throw new NotImplementedException(); + } + + public bool UseTrashForRemove(File file) { return file.RootFolderType != FolderType.TRASH; } - public static string GetUniqFileDirectory(object fileIdObject) + public string GetUniqFileDirectory(int fileId) { - if (fileIdObject == null) throw new ArgumentNullException("fileIdObject"); - var fileIdInt = Convert.ToInt32(Convert.ToString(fileIdObject)); - return string.Format("folder_{0}/file_{1}", (fileIdInt / 1000 + 1) * 1000, fileIdInt); + if (fileId == 0) throw new ArgumentNullException("fileIdObject"); + return string.Format("folder_{0}/file_{1}", (Convert.ToInt32(fileId) / 1000 + 1) * 1000, fileId); } - public static string GetUniqFilePath(File file) + public string GetUniqFilePath(File file) { return file != null ? GetUniqFilePath(file, "content" + FileUtility.GetFileExtension(file.PureTitle)) : null; } - public static string GetUniqFilePath(File file, string fileTitle) + public string GetUniqFilePath(File file, string fileTitle) { return file != null ? string.Format("{0}/{1}", GetUniqFileVersionPath(file.ID, file.Version), fileTitle) : null; } - public static string GetUniqFileVersionPath(object fileIdObject, int version) + public string GetUniqFileVersionPath(int fileId, int version) { - return fileIdObject != null - ? string.Format("{0}/v{1}", GetUniqFileDirectory(fileIdObject), version) + return fileId != null + ? string.Format("{0}/v{1}", GetUniqFileDirectory(fileId), version) : null; } @@ -864,12 +975,22 @@ namespace ASC.Files.Core.Data #region chunking - public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + throw new NotImplementedException(); + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) { return ChunkedUploadSessionHolder.CreateUploadSession(file, contentLength); } - public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + throw new NotImplementedException(); + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) { if (!uploadSession.UseChunks) { @@ -892,7 +1013,7 @@ namespace ASC.Files.Core.Data } } - private File FinalizeUploadSession(ChunkedUploadSession uploadSession) + private File FinalizeUploadSession(ChunkedUploadSession uploadSession) { ChunkedUploadSessionHolder.FinalizeUploadSession(uploadSession); @@ -903,14 +1024,19 @@ namespace ASC.Files.Core.Data return file; } - public void AbortUploadSession(ChunkedUploadSession uploadSession) + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + throw new NotImplementedException(); + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) { ChunkedUploadSessionHolder.AbortUploadSession(uploadSession); } - private File GetFileForCommit(ChunkedUploadSession uploadSession) + private File GetFileForCommit(ChunkedUploadSession uploadSession) { - if (uploadSession.File.ID != null) + if (uploadSession.File.ID != default) { var file = GetFile(uploadSession.File.ID); file.Version++; @@ -920,7 +1046,7 @@ namespace ASC.Files.Core.Data file.Encrypted = uploadSession.Encrypted; return file; } - var result = ServiceProvider.GetService(); + var result = ServiceProvider.GetService>(); result.FolderID = uploadSession.File.FolderID; result.Title = uploadSession.File.Title; result.ContentLength = uploadSession.BytesTotal; @@ -935,10 +1061,15 @@ namespace ASC.Files.Core.Data #region Only in TMFileDao public void ReassignFiles(object[] fileIds, Guid newOwnerId) + { + throw new NotImplementedException(); + } + + public void ReassignFiles(int[] fileIds, Guid newOwnerId) { var toUpdate = Query(FilesDbContext.Files) .Where(r => r.CurrentVersion) - .Where(r => fileIds.Any(a => a.ToString() == r.Id.ToString())); + .Where(r => fileIds.Any(a => a == r.Id)); foreach (var f in toUpdate) { @@ -950,11 +1081,16 @@ namespace ASC.Files.Core.Data public List GetFiles(object[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) { - if (parentIds == null || parentIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List(); + throw new NotImplementedException(); + } + + public List> GetFiles(int[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (parentIds == null || parentIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); var q = GetFileQuery(r => r.CurrentVersion) .Join(FilesDbContext.Tree, a => a.FolderId, t => t.FolderId, (file, tree) => new { file, tree }) - .Where(r => parentIds.Any(a => a.ToString() == r.tree.ParentId.ToString())) + .Where(r => parentIds.Any(a => a == r.tree.ParentId)) .Select(r => r.file); if (!string.IsNullOrEmpty(searchText)) @@ -1006,6 +1142,11 @@ namespace ASC.Files.Core.Data } public IEnumerable Search(string searchText, bool bunch) + { + throw new NotImplementedException(); + } + + IEnumerable> IFileDao.Search(string searchText, bool bunch) { if (FactoryIndexer.TrySelectIds(s => s.MatchAll(searchText), out var ids)) { @@ -1030,12 +1171,17 @@ namespace ASC.Files.Core.Data } } - private void DeleteFolder(object fileId) + private void DeleteFolder(int fileId) { GlobalStore.GetStore().DeleteDirectory(GetUniqFileDirectory(fileId)); } public bool IsExistOnStorage(File file) + { + throw new NotImplementedException(); + } + + public bool IsExistOnStorage(File file) { return GlobalStore.GetStore().IsFile(GetUniqFilePath(file)); } @@ -1043,6 +1189,11 @@ namespace ASC.Files.Core.Data private const string DiffTitle = "diff.zip"; public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + throw new NotImplementedException(); + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) { if (file == null) throw new ArgumentNullException("file"); if (string.IsNullOrEmpty(changes)) throw new ArgumentNullException("changes"); @@ -1051,7 +1202,7 @@ namespace ASC.Files.Core.Data changes = changes.Trim(); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)file.ID) + .Where(r => r.Id == file.ID) .Where(r => r.Version == file.Version); foreach (var f in toUpdate) @@ -1065,9 +1216,14 @@ namespace ASC.Files.Core.Data } public List GetEditHistory(DocumentServiceHelper documentServiceHelper, object fileId, int fileVersion = 0) + { + throw new NotImplementedException(); + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, int fileId, int fileVersion = 0) { var query = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Forcesave == ForcesaveType.None); if (fileVersion > 0) @@ -1099,14 +1255,24 @@ namespace ASC.Files.Core.Data } public Stream GetDifferenceStream(File file) + { + throw new NotImplementedException(); + } + + public Stream GetDifferenceStream(File file) { return GlobalStore.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file, DiffTitle)); } public bool ContainChanges(object fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public bool ContainChanges(int fileId, int fileVersion) { return Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId) + .Where(r => r.Id == fileId) .Where(r => r.Version == fileVersion) .Where(r => r.Changes != null) .Any(); @@ -1160,7 +1326,7 @@ namespace ASC.Files.Core.Data { if (subjectGroup) { - var users = UserManager.GetUsersByGroup(subjectID).Select(u => u.ID.ToString()).ToArray(); + var users = UserManager.GetUsersByGroup(subjectID).Select(u => u.ID).ToArray(); result.In(r => r.CreateBy, users); } else @@ -1185,7 +1351,7 @@ namespace ASC.Files.Core.Data }; } - protected List FromQueryWithShared(IQueryable dbFiles) + protected List> FromQueryWithShared(IQueryable dbFiles) { return dbFiles .Select(r => new DbFileQuery @@ -1210,32 +1376,7 @@ namespace ASC.Files.Core.Data .ToList(); } - protected List> FromQueryWithSharedInt(IQueryable dbFiles) - { - return dbFiles - .Select(r => new DbFileQuery - { - file = r, - root = - FilesDbContext.Folders - .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) - .Where(x => x.folder.TenantId == r.TenantId) - .Where(x => x.tree.FolderId == r.FolderId) - .OrderByDescending(r => r.tree.Level) - .Select(r => r.folder) - .FirstOrDefault(), - shared = - FilesDbContext.Security - .Where(x => x.EntryType == FileEntryType.File) - .Where(x => x.EntryId == r.Id.ToString()) - .Any() - }) - .ToList() - .Select(ToFileInt) - .ToList(); - } - - protected List FromQuery(IQueryable dbFiles) + protected List> FromQuery(IQueryable dbFiles) { return dbFiles .Select(r => new DbFileQuery @@ -1255,31 +1396,7 @@ namespace ASC.Files.Core.Data .ToList(); } - public File ToFile(DbFileQuery r) - { - var file = ServiceProvider.GetService(); - file.ID = r.file.Id; - file.Title = r.file.Title; - file.FolderID = r.file.FolderId; - file.CreateOn = TenantUtil.DateTimeFromUtc(r.file.CreateOn); - file.CreateBy = r.file.CreateBy; - file.Version = r.file.Version; - file.VersionGroup = r.file.VersionGroup; - file.ContentLength = r.file.ContentLength; - file.ModifiedOn = TenantUtil.DateTimeFromUtc(r.file.ModifiedOn); - file.ModifiedBy = r.file.ModifiedBy; - file.RootFolderType = r.root?.FolderType ?? default; - file.RootFolderCreator = r.root?.CreateBy ?? default; - file.RootFolderId = r.root?.Id ?? default; - file.Shared = r.shared; - file.ConvertedType = r.file.ConvertedType; - file.Comment = r.file.Comment; - file.Encrypted = r.file.Encrypted; - file.Forcesave = r.file.Forcesave; - return file; - } - - public File ToFileInt(DbFileQuery r) + public File ToFile(DbFileQuery r) { var file = ServiceProvider.GetService>(); file.ID = r.file.Id; @@ -1302,169 +1419,6 @@ namespace ASC.Files.Core.Data file.Forcesave = r.file.Forcesave; return file; } - - - ///test:test - - public File GetFile(int fileId, int fileVersion) - { - throw new NotImplementedException(); - } - - public File GetFile(int parentId, string title) - { - throw new NotImplementedException(); - } - - public File GetFileStable(int fileId, int fileVersion = -1) - { - throw new NotImplementedException(); - } - - public List> GetFileHistory(int fileId) - { - throw new NotImplementedException(); - } - - public List> GetFiles(int[] fileIds) - { - throw new NotImplementedException(); - } - - public List> GetFilesForShare(int[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) - { - throw new NotImplementedException(); - } - - public List GetFiles(int parentId) - { - throw new NotImplementedException(); - } - - public List> GetFiles(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) - { - throw new NotImplementedException(); - } - - public Stream GetFileStream(File file) - { - throw new NotImplementedException(); - } - - public Stream GetFileStream(File file, long offset) - { - throw new NotImplementedException(); - } - - public Uri GetPreSignedUri(File file, TimeSpan expires) - { - throw new NotImplementedException(); - } - - public bool IsSupportedPreSignedUri(File file) - { - throw new NotImplementedException(); - } - - public File SaveFile(File file, Stream fileStream) - { - throw new NotImplementedException(); - } - - public File ReplaceFileVersion(File file, Stream fileStream) - { - throw new NotImplementedException(); - } - - public void DeleteFile(int fileId) - { - throw new NotImplementedException(); - } - - public bool IsExist(string title, int folderId) - { - throw new NotImplementedException(); - } - - public object MoveFile(int fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - public File CopyFile(int fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - public object FileRename(File file, string newTitle) - { - throw new NotImplementedException(); - } - - public string UpdateComment(int fileId, int fileVersion, string comment) - { - throw new NotImplementedException(); - } - - public void CompleteVersion(int fileId, int fileVersion) - { - throw new NotImplementedException(); - } - - public void ContinueVersion(int fileId, int fileVersion) - { - throw new NotImplementedException(); - } - - public bool UseTrashForRemove(File file) - { - throw new NotImplementedException(); - } - - public ChunkedUploadSession CreateUploadSession(File file, long contentLength) - { - throw new NotImplementedException(); - } - - public void ReassignFiles(int[] fileIds, Guid newOwnerId) - { - throw new NotImplementedException(); - } - - public List> GetFiles(int[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) - { - throw new NotImplementedException(); - } - - IEnumerable> IFileDao.Search(string text, bool bunch) - { - throw new NotImplementedException(); - } - - public bool IsExistOnStorage(File file) - { - throw new NotImplementedException(); - } - - public void SaveEditHistory(File file, string changes, Stream differenceStream) - { - throw new NotImplementedException(); - } - - public List GetEditHistory(DocumentServiceHelper documentServiceHelper, int fileId, int fileVersion = 0) - { - throw new NotImplementedException(); - } - - public Stream GetDifferenceStream(File file) - { - throw new NotImplementedException(); - } - - public bool ContainChanges(int fileId, int fileVersion) - { - throw new NotImplementedException(); - } } public class DbFileQuery diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index 946b326e7f..e09f0c8e1f 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -50,7 +50,7 @@ using Microsoft.Extensions.Options; namespace ASC.Files.Core.Data { - public class FolderDao : AbstractDao, IFolderDao + public class FolderDao : AbstractDao, IFolderDao, IFolderDao { private const string my = "my"; private const string common = "common"; @@ -99,24 +99,38 @@ namespace ASC.Files.Core.Data public Folder GetFolder(object folderId) { - var query = GetFolderQuery(r => r.Id.ToString() == folderId.ToString()); + throw new NotImplementedException(); + } + + public Folder GetFolder(int folderId) + { + var query = GetFolderQuery(r => r.Id == folderId); return FromQueryWithShared(query).SingleOrDefault(); } public Folder GetFolder(string title, object parentId) + { + throw new NotImplementedException(); + } + + public Folder GetFolder(string title, int parentId) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(title); - var query = GetFolderQuery(r => r.Title == title && r.ParentId.ToString() == parentId.ToString()) + var query = GetFolderQuery(r => r.Title == title && r.ParentId == parentId) .OrderBy(r => r.CreateOn); return FromQueryWithShared(query).FirstOrDefault(); } public Folder GetRootFolder(object folderId) + { + throw new NotImplementedException(); + } + public Folder GetRootFolder(int folderId) { var id = FilesDbContext.Tree - .Where(r => r.FolderId == (int)folderId) + .Where(r => r.FolderId == folderId) .OrderByDescending(r => r.Level) .Select(r => r.ParentId) .FirstOrDefault(); @@ -127,9 +141,13 @@ namespace ASC.Files.Core.Data } public Folder GetRootFolderByFile(object fileId) + { + throw new NotImplementedException(); + } + public Folder GetRootFolderByFile(int fileId) { var subq = Query(FilesDbContext.Files) - .Where(r => r.Id == (int)fileId && r.CurrentVersion) + .Where(r => r.Id == fileId && r.CurrentVersion) .Select(r => r.FolderId) .Distinct(); @@ -144,17 +162,26 @@ namespace ASC.Files.Core.Data } public List GetFolders(object parentId) + { + throw new NotImplementedException(); + } + public List> GetFolders(int parentId) { return GetFolders(parentId, default, default, false, default, string.Empty); } public List GetFolders(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + throw new NotImplementedException(); + } + + public List> GetFolders(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) { if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) - return new List(); + return new List>(); if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); @@ -164,7 +191,7 @@ namespace ASC.Files.Core.Data { q = GetFolderQuery() .Join(FilesDbContext.Tree, r => r.Id, a => a.FolderId, (folder, tree) => new { folder, tree }) - .Where(r => r.tree.ParentId.ToString() == parentId.ToString() && r.tree.Level != 0) + .Where(r => r.tree.ParentId == parentId && r.tree.Level != 0) .Select(r => r.folder); } @@ -216,21 +243,25 @@ namespace ASC.Files.Core.Data } public List GetFolders(object[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + throw new NotImplementedException(); + } + + public List> GetFolders(int[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) { if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) - return new List(); + return new List>(); - var folderIdsStrings = folderIds.Select(r => r.ToString()).ToList(); - var q = GetFolderQuery(r => folderIdsStrings.Any(q => q == r.Id.ToString())); + var q = GetFolderQuery(r => folderIds.Any(q => q == r.Id)); if (searchSubfolders) { q = GetFolderQuery() .Join(FilesDbContext.Tree, r => r.Id, a => a.FolderId, (folder, tree) => new { folder, tree }) - .Where(r => folderIdsStrings.Any(q => q == r.folder.ParentId.ToString())) + .Where(r => folderIds.Any(q => q == r.folder.ParentId)) .Select(r => r.folder); } @@ -269,10 +300,14 @@ namespace ASC.Files.Core.Data public List GetParentFolders(object folderId) { - var folderIdString = folderId.ToString(); + throw new NotImplementedException(); + } + + public List> GetParentFolders(int folderId) + { var q = GetFolderQuery() .Join(FilesDbContext.Tree, r => r.Id, a => a.ParentId, (folder, tree) => new { folder, tree }) - .Where(r => r.tree.FolderId.ToString() == folderIdString) + .Where(r => r.tree.FolderId == folderId) .OrderByDescending(r => r.tree.Level) .Select(r => r.folder); @@ -280,6 +315,11 @@ namespace ASC.Files.Core.Data } public object SaveFolder(Folder folder) + { + throw new NotImplementedException(); + } + + public int SaveFolder(Folder folder) { if (folder == null) throw new ArgumentNullException("folder"); @@ -295,10 +335,10 @@ namespace ASC.Files.Core.Data using (var tx = FilesDbContext.Database.BeginTransaction()) { - if (folder.ID != null && IsExist(folder.ID)) + if (folder.ID != default && IsExist(folder.ID)) { var toUpdate = Query(FilesDbContext.Folders) - .Where(r => r.Id == (int)folder.ID) + .Where(r => r.Id == folder.ID) .FirstOrDefault(); toUpdate.Title = folder.Title; @@ -314,7 +354,7 @@ namespace ASC.Files.Core.Data var newFolder = new DbFolder { Id = 0, - ParentId = (int)folder.ParentFolderID, + ParentId = folder.ParentFolderID, Title = folder.Title, CreateOn = TenantUtil.DateTimeToUtc(folder.CreateOn), CreateBy = folder.CreateBy, @@ -331,8 +371,8 @@ namespace ASC.Files.Core.Data //itself link var newTree = new DbFolderTree { - FolderId = (int)folder.ID, - ParentId = (int)folder.ID, + FolderId = folder.ID, + ParentId = folder.ID, Level = 0 }; @@ -341,12 +381,12 @@ namespace ASC.Files.Core.Data //full path to root var oldTree = FilesDbContext.Tree - .Where(r => r.FolderId == (int)folder.ParentFolderID) + .Where(r => r.FolderId == folder.ParentFolderID) .FirstOrDefault(); var treeToAdd = new DbFolderTree { - FolderId = (int)folder.ID, + FolderId = folder.ID, ParentId = oldTree.ParentId, Level = oldTree.Level + 1 }; @@ -367,20 +407,20 @@ namespace ASC.Files.Core.Data return folder.ID; } - private bool IsExist(object folderId) + private bool IsExist(int folderId) { return Query(FilesDbContext.Folders) - .Where(r => r.Id == (int)folderId) + .Where(r => r.Id == folderId) .Any(); } public void DeleteFolder(object folderId) { - if (folderId == null) throw new ArgumentNullException("folderId"); - - var id = int.Parse(Convert.ToString(folderId)); - - if (id == 0) return; + throw new NotImplementedException(); + } + public void DeleteFolder(int id) + { + if (id == default) throw new ArgumentNullException("folderId"); using (var tx = FilesDbContext.Database.BeginTransaction()) { @@ -431,10 +471,14 @@ namespace ASC.Files.Core.Data RecalculateFoldersCount(parent); } - FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = (int)folderId }); + FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = (int)id }); } public object MoveFolder(object folderId, object toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + public int MoveFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { using (var tx = FilesDbContext.Database.BeginTransaction()) { @@ -443,26 +487,26 @@ namespace ASC.Files.Core.Data if (folder.FolderType != FolderType.DEFAULT) throw new ArgumentException("It is forbidden to move the System folder.", "folderId"); - var recalcFolders = new List { toFolderId }; + var recalcFolders = new List { toFolderId }; var parent = FilesDbContext.Folders - .Where(r => r.Id == (int)folderId) + .Where(r => r.Id == folderId) .Select(r => r.ParentId) .FirstOrDefault(); if (parent != 0 && !recalcFolders.Contains(parent)) recalcFolders.Add(parent); var toUpdate = Query(FilesDbContext.Folders) - .Where(r => r.Id == (int)folderId) + .Where(r => r.Id == folderId) .FirstOrDefault(); - toUpdate.ParentId = (int)toFolderId; + toUpdate.ParentId = toFolderId; toUpdate.ModifiedOn = DateTime.UtcNow; toUpdate.ModifiedBy = AuthContext.CurrentAccount.ID; FilesDbContext.SaveChanges(); var subfolders = FilesDbContext.Tree - .Where(r => r.ParentId == (int)folderId) + .Where(r => r.ParentId == folderId) .ToDictionary(r => r.FolderId, r => r.Level); var toDelete = FilesDbContext.Tree @@ -472,7 +516,7 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); var toInsert = FilesDbContext.Tree - .Where(r => r.FolderId == (int)toFolderId) + .Where(r => r.FolderId == toFolderId) .ToList(); foreach (var subfolder in subfolders) @@ -499,6 +543,10 @@ namespace ASC.Files.Core.Data } public Folder CopyFolder(object folderId, object toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + public Folder CopyFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { var folder = GetFolder(folderId); @@ -507,7 +555,7 @@ namespace ASC.Files.Core.Data if (folder.FolderType == FolderType.BUNCH) folder.FolderType = FolderType.DEFAULT; - var copy = ServiceProvider.GetService(); + var copy = ServiceProvider.GetService>(); copy.ParentFolderID = toFolderId; copy.RootFolderId = toFolder.RootFolderId; copy.RootFolderCreator = toFolder.RootFolderCreator; @@ -523,13 +571,17 @@ namespace ASC.Files.Core.Data public IDictionary CanMoveOrCopy(object[] folderIds, object to) { - var result = new Dictionary(); + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(int[] folderIds, int to) + { + var result = new Dictionary(); foreach (var folderId in folderIds) { var exists = FilesDbContext.Tree - .Where(r => r.ParentId == (int)folderId) - .Where(r => r.FolderId == (int)to) + .Where(r => r.ParentId == folderId) + .Where(r => r.FolderId == to) .Any(); if (exists) @@ -538,13 +590,13 @@ namespace ASC.Files.Core.Data } var title = Query(FilesDbContext.Folders) - .Where(r => r.Id == (int)folderId) + .Where(r => r.Id == folderId) .Select(r => r.Title.ToLower()) .FirstOrDefault(); var conflict = Query(FilesDbContext.Folders) .Where(r => r.Title.ToLower() == title) - .Where(r => r.ParentId == (int)to) + .Where(r => r.ParentId == to) .Select(r => r.Id) .FirstOrDefault(); @@ -552,15 +604,15 @@ namespace ASC.Files.Core.Data { FilesDbContext.Files .Join(FilesDbContext.Files, f1 => f1.Title.ToLower(), f2 => f2.Title.ToLower(), (f1, f2) => new { f1, f2 }) - .Where(r => r.f1.TenantId == TenantID && r.f1.CurrentVersion && r.f1.FolderId == (int)folderId) - .Where(r => r.f2.TenantId == TenantID && r.f2.CurrentVersion && r.f2.FolderId == (int)conflict) + .Where(r => r.f1.TenantId == TenantID && r.f1.CurrentVersion && r.f1.FolderId == folderId) + .Where(r => r.f2.TenantId == TenantID && r.f2.CurrentVersion && r.f2.FolderId == conflict) .Select(r => r.f1) .ToList() .ForEach(r => result[r.Id] = r.Title); var childs = Query(FilesDbContext.Folders) - .Where(r => r.ParentId == (int)folderId) - .Select(r => r.Id.ToString()); + .Where(r => r.ParentId == folderId) + .Select(r => r.Id); foreach (var pair in CanMoveOrCopy(childs.ToArray(), conflict)) { @@ -573,9 +625,14 @@ namespace ASC.Files.Core.Data } public object RenameFolder(Folder folder, string newTitle) + { + throw new NotImplementedException(); + } + + public int RenameFolder(Folder folder, string newTitle) { var toUpdate = Query(FilesDbContext.Folders) - .Where(r => r.Id == (int)folder.ID) + .Where(r => r.Id == folder.ID) .FirstOrDefault(); toUpdate.Title = Global.ReplaceInvalidCharsAndTruncate(newTitle); @@ -588,52 +645,82 @@ namespace ASC.Files.Core.Data } public int GetItemsCount(object folderId) + { + throw new NotImplementedException(); + } + + public int GetItemsCount(int folderId) { return GetFoldersCount(folderId) + GetFilesCount(folderId); } - private int GetFoldersCount(object parentId) + private int GetFoldersCount(int parentId) { var count = FilesDbContext.Tree - .Where(r => r.ParentId == (int)parentId) + .Where(r => r.ParentId == parentId) .Where(r => r.Level >= 0) .Count(); return count; } - private int GetFilesCount(object folderId) + private int GetFilesCount(int folderId) { var count = Query(FilesDbContext.Files) .Distinct() - .Where(r => FilesDbContext.Tree.Where(r => r.ParentId == (int)folderId).Select(r => r.FolderId).Any(b => b == r.FolderId)) + .Where(r => FilesDbContext.Tree.Where(r => r.ParentId == folderId).Select(r => r.FolderId).Any(b => b == r.FolderId)) .Count(); return count; } public bool IsEmpty(object folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(int folderId) { return GetItemsCount(folderId) == 0; } public bool UseTrashForRemove(Folder folder) + { + throw new NotImplementedException(); + } + + public bool UseTrashForRemove(Folder folder) { return folder.RootFolderType != FolderType.TRASH && folder.FolderType != FolderType.BUNCH; } public bool UseRecursiveOperation(object folderId, object toRootFolderId) + { + throw new NotImplementedException(); + } + + public bool UseRecursiveOperation(int folderId, int toRootFolderId) { return true; } public bool CanCalculateSubitems(object entryId) + { + throw new NotImplementedException(); + } + + public bool CanCalculateSubitems(int entryId) { return true; } public long GetMaxUploadSize(object folderId, bool chunkedUpload) + { + throw new NotImplementedException(); + } + + public long GetMaxUploadSize(int folderId, bool chunkedUpload) { var tmp = long.MaxValue; @@ -643,15 +730,15 @@ namespace ASC.Files.Core.Data return Math.Min(tmp, chunkedUpload ? SetupInfo.MaxChunkedUploadSize(TenantExtra, TenantStatisticProvider) : SetupInfo.MaxUploadSize(TenantExtra, TenantStatisticProvider)); } - private void RecalculateFoldersCount(object id) + private void RecalculateFoldersCount(int id) { var toUpdate = Query(FilesDbContext.Folders) - .Where(r => FilesDbContext.Tree.Where(a => a.FolderId == (int)id).Select(a => a.ParentId).Any(a => a == r.Id)) + .Where(r => FilesDbContext.Tree.Where(a => a.FolderId == id).Select(a => a.ParentId).Any(a => a == r.Id)) .ToList(); foreach (var f in toUpdate) { - var count = FilesDbContext.Tree.Where(r => r.ParentId == (int)id).Count() - 1; + var count = FilesDbContext.Tree.Where(r => r.ParentId == id).Count() - 1; f.FoldersCount = count; } @@ -661,9 +748,14 @@ namespace ASC.Files.Core.Data #region Only for TMFolderDao public void ReassignFolders(object[] folderIds, Guid newOwnerId) + { + throw new NotImplementedException(); + } + + public void ReassignFolders(int[] folderIds, Guid newOwnerId) { var toUpdate = Query(FilesDbContext.Folders) - .Where(r => folderIds.Any(a => r.Id == (int)a)); + .Where(r => folderIds.Any(a => r.Id == a)); foreach (var f in toUpdate) { @@ -674,15 +766,20 @@ namespace ASC.Files.Core.Data } public IEnumerable Search(string text, bool bunch) + { + throw new NotImplementedException(); + } + + IEnumerable> IFolderDao.Search(string text, bool bunch) { return Search(text).Where(f => bunch ? f.RootFolderType == FolderType.BUNCH : (f.RootFolderType == FolderType.USER || f.RootFolderType == FolderType.COMMON)).ToList(); } - private IEnumerable Search(string text) + private IEnumerable> Search(string text) { - if (string.IsNullOrEmpty(text)) return new List(); + if (string.IsNullOrEmpty(text)) return new List>(); if (FactoryIndexer.TrySelectIds(s => s.MatchAll(text), out var ids)) { @@ -695,6 +792,11 @@ namespace ASC.Files.Core.Data } public virtual IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -705,14 +807,14 @@ namespace ASC.Files.Core.Data .Where(r => keys.Length > 1 ? keys.Any(a => a == r.RightNode) : r.RightNode == keys[0]) .ToDictionary(r => r.RightNode, r => r.LeftNode); - var folderIds = new List(); + var folderIds = new List(); foreach (var key in keys) { - string folderId = null; - if (createIfNotExists && !folderIdsDictionary.TryGetValue(key, out folderId)) + int newFolderId = 0; + if (createIfNotExists && !folderIdsDictionary.TryGetValue(key, out var folderId)) { - var folder = ServiceProvider.GetService(); + var folder = ServiceProvider.GetService>(); switch (bunch) { case my: @@ -742,11 +844,11 @@ namespace ASC.Files.Core.Data } using var tx = FilesDbContext.Database.BeginTransaction();//NOTE: Maybe we shouldn't start transaction here at all - folderId = (string)SaveFolder(folder); //Save using our db manager + newFolderId = SaveFolder(folder); //Save using our db manager var newBunch = new DbFilesBunchObjects { - LeftNode = folderId, + LeftNode = newFolderId.ToString(), RightNode = key, TenantId = TenantID }; @@ -756,12 +858,17 @@ namespace ASC.Files.Core.Data tx.Commit(); //Commit changes } - folderIds.Add(folderId); + folderIds.Add(newFolderId); } return folderIds; } public virtual object GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public virtual int GetFolderID(string module, string bunch, Guid data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -772,16 +879,17 @@ namespace ASC.Files.Core.Data .Select(r => r.LeftNode) .FirstOrDefault(); + int newFolderId = 0; if (createIfNotExists && folderId == null) { - var folder = ServiceProvider.GetService(); + var folder = ServiceProvider.GetService>(); folder.ParentFolderID = 0; switch (bunch) { case my: folder.FolderType = FolderType.USER; folder.Title = my; - folder.CreateBy = new Guid(data); + folder.CreateBy = data; break; case common: folder.FolderType = FolderType.COMMON; @@ -790,7 +898,7 @@ namespace ASC.Files.Core.Data case trash: folder.FolderType = FolderType.TRASH; folder.Title = trash; - folder.CreateBy = new Guid(data); + folder.CreateBy = data; break; case share: folder.FolderType = FolderType.SHARE; @@ -806,10 +914,10 @@ namespace ASC.Files.Core.Data break; } using var tx = FilesDbContext.Database.BeginTransaction(); //NOTE: Maybe we shouldn't start transaction here at all - folderId = (string)SaveFolder(folder); //Save using our db manager + newFolderId = SaveFolder(folder); //Save using our db manager var toInsert = new DbFilesBunchObjects { - LeftNode = folderId, + LeftNode = newFolderId.ToString(), RightNode = key, TenantId = TenantID }; @@ -818,28 +926,48 @@ namespace ASC.Files.Core.Data tx.Commit(); //Commit changes } - return Convert.ToInt32(folderId); + return newFolderId; } public object GetFolderIDProjects(bool createIfNotExists) { - return GetFolderID(FileConstant.ModuleId, projects, null, createIfNotExists); + throw new NotImplementedException(); + } + + int IFolderDao.GetFolderIDProjects(bool createIfNotExists) + { + return GetFolderID(FileConstant.ModuleId, projects, Guid.Empty, createIfNotExists); } public object GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) { - return GetFolderID(FileConstant.ModuleId, trash, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); + throw new NotImplementedException(); + } + + int IFolderDao.GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) + { + return GetFolderID(FileConstant.ModuleId, trash, (userId ?? AuthContext.CurrentAccount.ID), createIfNotExists); } public object GetFolderIDCommon(bool createIfNotExists) { - return GetFolderID(FileConstant.ModuleId, common, null, createIfNotExists); + throw new NotImplementedException(); + } + + int IFolderDao.GetFolderIDCommon(bool createIfNotExists) + { + return GetFolderID(FileConstant.ModuleId, common, Guid.Empty, createIfNotExists); } public object GetFolderIDUser(bool createIfNotExists, Guid? userId = null) { - return GetFolderID(FileConstant.ModuleId, my, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); + throw new NotImplementedException(); + } + + int IFolderDao.GetFolderIDUser(bool createIfNotExists, Guid? userId = null) + { + return GetFolderID(FileConstant.ModuleId, my, (userId ?? AuthContext.CurrentAccount.ID), createIfNotExists); } public object GetFolderIDShare(bool createIfNotExists) @@ -847,6 +975,11 @@ namespace ASC.Files.Core.Data return GetFolderID(FileConstant.ModuleId, share, null, createIfNotExists); } + int IFolderDao.GetFolderIDShare(bool createIfNotExists) + { + return GetFolderID(FileConstant.ModuleId, share, Guid.Empty, createIfNotExists); + } + #endregion protected IQueryable GetFolderQuery(Expression> where = null) @@ -859,7 +992,7 @@ namespace ASC.Files.Core.Data return q; } - protected List FromQueryWithShared(IQueryable dbFiles) + protected List> FromQueryWithShared(IQueryable dbFiles) { return dbFiles .Select(r => new DbFolderQuery @@ -883,7 +1016,7 @@ namespace ASC.Files.Core.Data .ToList(); } - protected List FromQuery(IQueryable dbFiles) + protected List> FromQuery(IQueryable dbFiles) { return dbFiles .Select(r => new DbFolderQuery @@ -904,9 +1037,9 @@ namespace ASC.Files.Core.Data .ToList(); } - public Folder ToFolder(DbFolderQuery r) + public Folder ToFolder(DbFolderQuery r) { - var result = ServiceProvider.GetService(); + var result = ServiceProvider.GetService>(); result.ID = r.folder.Id; result.ParentFolderID = r.folder.ParentId; result.Title = r.folder.Title; @@ -959,14 +1092,23 @@ namespace ASC.Files.Core.Data } public string GetBunchObjectID(object folderID) + { + throw new NotImplementedException(); + } + public string GetBunchObjectID(int folderID) { return Query(FilesDbContext.BunchObjects) - .Where(r => r.LeftNode == (folderID ?? string.Empty).ToString()) + .Where(r => r.LeftNode == (folderID).ToString()) .Select(r => r.RightNode) .FirstOrDefault(); } public Dictionary GetBunchObjectIDs(List folderIDs) + { + throw new NotImplementedException(); + } + + public Dictionary GetBunchObjectIDs(List folderIDs) { return Query(FilesDbContext.BunchObjects) .Where(r => folderIDs.Any(a => a.ToString() == r.LeftNode)) diff --git a/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs b/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs index 3b5832e31e..41771190fc 100644 --- a/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs +++ b/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs @@ -40,23 +40,23 @@ namespace ASC.Files.Core { [DebuggerDisplay("{Id} into {FolderId}")] [Serializable] - public class ChunkedUploadSession : CommonChunkedUploadSession + public class ChunkedUploadSession : CommonChunkedUploadSession { - public string FolderId { get; set; } + public T FolderId { get; set; } - public File File { get; set; } + public File File { get; set; } public bool Encrypted { get; set; } - public ChunkedUploadSession(File file, long bytesTotal) : base(bytesTotal) + public ChunkedUploadSession(File file, long bytesTotal) : base(bytesTotal) { File = file; } public override object Clone() { - var clone = (ChunkedUploadSession)MemberwiseClone(); - clone.File = (File)File.Clone(); + var clone = (ChunkedUploadSession)MemberwiseClone(); + clone.File = (File)File.Clone(); return clone; } } @@ -73,7 +73,7 @@ namespace ASC.Files.Core } - public object ToResponseObject(ChunkedUploadSession session, bool appendBreadCrumbs = false) + public object ToResponseObject(ChunkedUploadSession session, bool appendBreadCrumbs = false) { var pathFolder = appendBreadCrumbs ? EntryManager.GetBreadCrumbs(session.FolderId).Select(f => diff --git a/products/ASC.Files/Server/Core/Entries/File.cs b/products/ASC.Files/Server/Core/Entries/File.cs index 6bcc24afd6..c990739434 100644 --- a/products/ASC.Files/Server/Core/Entries/File.cs +++ b/products/ASC.Files/Server/Core/Entries/File.cs @@ -59,6 +59,22 @@ namespace ASC.Files.Core [DataMember(Name = "id")] public new T ID { get; set; } + public new T FolderID { get; set; } + + private T _folderIdDisplay; + + [DataMember(Name = "folder_id")] + public new T FolderIdDisplay + { + get + { + if (_folderIdDisplay != null) return _folderIdDisplay; + + return FolderID; + } + set { _folderIdDisplay = value; } + } + public File(Global global, FilesLinkUtility filesLinkUtility, FileUtility fileUtility, FileConverter fileConverter) : base(global, filesLinkUtility, fileUtility, fileConverter) { } @@ -229,6 +245,20 @@ namespace ASC.Files.Core public FileUtility FileUtility { get; } public FileConverter FileConverter { get; } + private object _folderIdDisplay; + + [DataMember(Name = "folder_id")] + public override object FolderIdDisplay + { + get + { + if (_folderIdDisplay != null) return _folderIdDisplay; + + return FolderID; + } + set { _folderIdDisplay = value; } + } + public static string Serialize(File file) { using (var ms = new FileEntrySerializer().ToXml(file)) diff --git a/products/ASC.Files/Server/Core/Entries/FileEntry.cs b/products/ASC.Files/Server/Core/Entries/FileEntry.cs index 91b2ce4f5d..5526ede63b 100644 --- a/products/ASC.Files/Server/Core/Entries/FileEntry.cs +++ b/products/ASC.Files/Server/Core/Entries/FileEntry.cs @@ -99,21 +99,10 @@ namespace ASC.Files.Core public string ProviderKey { get; set; } [DataMember(Name = "folder_id")] - public object FolderIdDisplay + public abstract object FolderIdDisplay { - get - { - if (_folderIdDisplay != null) return _folderIdDisplay; - - var folder = this as Folder; - if (folder != null) return folder.ParentFolderID; - - var file = this as File; - if (file != null) return file.FolderID; - - return null; - } - set { _folderIdDisplay = value; } + get; + set; } public bool ProviderEntry @@ -144,7 +133,6 @@ namespace ASC.Files.Core private string _modifiedByString; private string _createByString; - private object _folderIdDisplay; public override bool Equals(object obj) { diff --git a/products/ASC.Files/Server/Core/Entries/Folder.cs b/products/ASC.Files/Server/Core/Entries/Folder.cs index f5d8d7bc93..b43c9a2f94 100644 --- a/products/ASC.Files/Server/Core/Entries/Folder.cs +++ b/products/ASC.Files/Server/Core/Entries/Folder.cs @@ -50,6 +50,32 @@ namespace ASC.Files.Core [EnumMember] Projects = 8 } + public class Folder : Folder + { + [DataMember(Name = "id")] + public new T ID { get; set; } + + public new T ParentFolderID { get; set; } + + private T _folderIdDisplay; + + [DataMember(Name = "folder_id")] + public new T FolderIdDisplay + { + get + { + if (_folderIdDisplay != null) return _folderIdDisplay; + + return ParentFolderID; + } + set { _folderIdDisplay = value; } + } + + public Folder(Global global) : base(global) + { + } + } + [DataContract(Name = "folder", Namespace = "")] [DebuggerDisplay("{Title} ({ID})")] public class Folder : FileEntry @@ -79,6 +105,20 @@ namespace ASC.Files.Core set { NewForMe = Convert.ToInt32(value); } } + private object _folderIdDisplay; + + [DataMember(Name = "folder_id")] + public override object FolderIdDisplay + { + get + { + if (_folderIdDisplay != null) return _folderIdDisplay; + + return ParentFolderID; + } + set { _folderIdDisplay = value; } + } + public Folder(Global global) : base(global) { diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 7ba1562192..c7cf2c9177 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -72,7 +72,7 @@ using UrlShortener = ASC.Web.Core.Utility.UrlShortener; namespace ASC.Web.Files.Services.WCFService { - public class FileStorageService : IFileStorageService + public class FileStorageService //: IFileStorageService { private static readonly FileEntrySerializer serializer = new FileEntrySerializer(); public Global Global { get; } @@ -234,12 +234,12 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(EntryManager.GetBreadCrumbs(folderId, folderDao).Select(f => f.ID)); } - public DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(ssubject) ? Guid.Empty : new Guid(ssubject); var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); Folder parent = null; try @@ -310,9 +310,9 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetFolderItemsXml(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public object GetFolderItemsXml(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { - var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); + var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(serializer.ToXml(folderItems)) @@ -321,16 +321,16 @@ namespace ASC.Web.Files.Services.WCFService return response; } - public ItemList GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string search) + public ItemList GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string search) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); var entries = Enumerable.Empty(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var folders = folderDao.GetFolders(foldersId.ToArray()).Cast(); folders = FileSecurity.FilterRead(folders); entries = entries.Concat(folders); @@ -343,10 +343,24 @@ namespace ASC.Web.Files.Services.WCFService foreach (var fileEntry in entries) { - if (fileEntry.RootFolderType == FolderType.USER - && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(fileEntry.FolderIdDisplay))) - fileEntry.FolderIdDisplay = GlobalFolderHelper.FolderShare; + if (fileEntry is File file) + { + if (fileEntry.RootFolderType == FolderType.USER + && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) + && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) + { + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } + } + else if (fileEntry is Folder folder) + { + if (fileEntry.RootFolderType == FolderType.USER + && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) + && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) + { + folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } + } } EntryManager.SetFileStatus(entries.OfType().Where(r => r.ID != null).ToList()); @@ -421,9 +435,9 @@ namespace ASC.Web.Files.Services.WCFService return folder; } - public File GetFile(string fileId, int version) + public File GetFile(T fileId, int version) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); fileDao.InvalidateCache(fileId); var file = version > 0 @@ -439,54 +453,30 @@ namespace ASC.Web.Files.Services.WCFService { var folderDao = GetFolderDao(); if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } return file; } - public File GetFile(int fileId, int version) - { - var fileDao = GetFileDao() as IFileDao; - fileDao.InvalidateCache(fileId); - - var file = version > 0 - ? fileDao.GetFile(fileId, version) - : fileDao.GetFile(fileId); - ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); - - EntryManager.SetFileStatus(file); - - if (file.RootFolderType == FolderType.USER - && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) - { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; - } - - return file; - } - - public ItemList GetSiblingsFile(string fileId, string parentId, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public ItemList> GetSiblingsFile(T fileId, T parentId, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); - var parent = folderDao.GetFolder(string.IsNullOrEmpty(parentId) ? file.FolderID : parentId); + var parent = folderDao.GetFolder(parentId == null || parentId.Equals(default) ? file.FolderID : parentId); ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); ErrorIf(parent.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); if (filter == FilterType.FoldersOnly) { - return new ItemList(); + return new ItemList>(); } if (filter == FilterType.None) { @@ -506,7 +496,7 @@ namespace ASC.Web.Files.Services.WCFService if (!FileSecurity.CanRead(parent)) { - file.FolderID = GlobalFolderHelper.FolderShare; + file.FolderID = GlobalFolderHelper.GetFolderShare(); entries = entries.Concat(new[] { file }); } else @@ -529,25 +519,25 @@ namespace ASC.Web.Files.Services.WCFService var result = FileSecurity.FilterRead(entries) - .OfType() + .OfType>() .Where(f => previewedType.Contains(FileUtility.GetFileTypeByFileName(f.Title))); - return new ItemList(result); + return new ItemList>(result); } - public File CreateNewFile(FileModel fileWrapper) + public File CreateNewFile(FileModel fileWrapper) { - if (string.IsNullOrEmpty(fileWrapper.Title) || string.IsNullOrEmpty(fileWrapper.ParentId)) throw new ArgumentException(); + if (string.IsNullOrEmpty(fileWrapper.Title) || fileWrapper.ParentId == null) throw new ArgumentException(); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(fileWrapper.ParentId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_CreateNewFolderInTrash); ErrorIf(!FileSecurity.CanCreate(folder), FilesCommonResource.ErrorMassage_SecurityException_Create); - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.FolderID = folder.ID; file.Comment = FilesCommonResource.CommentCreate; @@ -622,12 +612,12 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemDictionary CheckEditing(ItemList filesId) + public ItemDictionary CheckEditing(ItemList filesId) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); var result = new ItemDictionary(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var ids = filesId.Where(FileTracker.IsEditing).Select(id => id).ToArray(); foreach (var file in fileDao.GetFiles(ids)) @@ -773,16 +763,16 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList GetFileHistory(string fileId) + public ItemList> GetFileHistory(T fileId) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId); ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); - return new ItemList(fileDao.GetFileHistory(fileId)); + return new ItemList>(fileDao.GetFileHistory(fileId)); } - public KeyValuePair> UpdateToVersion(string fileId, int version) + public KeyValuePair>> UpdateToVersion(T fileId, int version) { var file = EntryManager.UpdateToVersionFile(fileId, version); FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture)); @@ -790,19 +780,19 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } - return new KeyValuePair>(file, GetFileHistory(fileId)); + return new KeyValuePair>>(file, GetFileHistory(fileId)); } - public string UpdateComment(string fileId, int version, string comment) + public string UpdateComment(T fileId, int version, string comment) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId, version); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); ErrorIf(!FileSecurity.CanEdit(file) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); @@ -816,7 +806,7 @@ namespace ASC.Web.Files.Services.WCFService return comment; } - public KeyValuePair> CompleteVersion(string fileId, int version, bool continueVersion) + public KeyValuePair>> CompleteVersion(T fileId, int version, bool continueVersion) { var file = EntryManager.CompleteVersionFile(fileId, version, continueVersion); @@ -827,18 +817,20 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + { + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } } - return new KeyValuePair>(file, GetFileHistory(fileId)); + return new KeyValuePair>>(file, GetFileHistory(fileId)); } - public File LockFile(string fileId, bool lockfile) + public File LockFile(T fileId, bool lockfile) { var tagDao = GetTagDao(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); @@ -892,17 +884,19 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + { + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } } return file; } - public ItemList GetEditHistory(string fileId, string doc = null) + public ItemList GetEditHistory(T fileId, string doc = null) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var readLink = FileShareLink.Check(doc, true, fileDao, out var file); if (file == null) file = fileDao.GetFile(fileId); @@ -914,14 +908,14 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(fileDao.GetEditHistory(DocumentServiceHelper, file.ID)); } - public EditHistoryData GetEditDiffUrl(string fileId, int version = 0, string doc = null) + public EditHistoryData GetEditDiffUrl(T fileId, int version = 0, string doc = null) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var readLink = FileShareLink.Check(doc, true, fileDao, out var file); if (file != null) { - fileId = file.ID.ToString(); + fileId = file.ID; } if (file == null @@ -990,10 +984,10 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList RestoreVersion(string fileId, int version, string url = null, string doc = null) + public ItemList RestoreVersion(T fileId, int version, string url = null, string doc = null) { - IFileDao fileDao; - File file; + IFileDao fileDao; + File file; if (string.IsNullOrEmpty(url)) { file = EntryManager.UpdateToVersionFile(fileId, version, doc); @@ -1001,7 +995,7 @@ namespace ASC.Web.Files.Services.WCFService else { string modifiedOnString; - fileDao = GetFileDao(); + fileDao = GetFileDao(); var fromFile = fileDao.GetFile(fileId, version); modifiedOnString = fromFile.ModifiedOnString; file = EntryManager.SaveEditing(fileId, null, url, null, doc, string.Format(FilesCommonResource.CommentRevertChanges, modifiedOnString)); @@ -1009,7 +1003,7 @@ namespace ASC.Web.Files.Services.WCFService FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture)); - fileDao = GetFileDao(); + fileDao = GetFileDao(); return new ItemList(fileDao.GetEditHistory(DocumentServiceHelper, file.ID)); } @@ -1027,7 +1021,7 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetNewItems(string folderId) + public object GetNewItems(string folderId) { try { @@ -1041,7 +1035,7 @@ namespace ASC.Web.Files.Services.WCFService if (!result.ToList().Any()) { - MarkAsRead(new ItemList { "folder_" + folderId }); + MarkAsRead(new ItemList { "folder_" + folderId }); } var response = new HttpResponseMessage(HttpStatusCode.OK) @@ -1057,11 +1051,11 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList MarkAsRead(ItemList items) + public ItemList MarkAsRead(ItemList items) { if (items.Count == 0) return GetTasksStatuses(); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return FileOperationsManagerHelper.MarkAsRead(foldersId, filesId); } @@ -1269,20 +1263,20 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Download(folders, files, GetHttpHeaders()); } - public ItemDictionary MoveOrCopyFilesCheck(ItemList items, string destFolderId) + public ItemDictionary MoveOrCopyFilesCheck(ItemList items, T destFolderId) { if (items.Count == 0) return new ItemDictionary(); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return new ItemDictionary(MoveOrCopyFilesCheck(filesId, foldersId, destFolderId)); } - private Dictionary MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, object destFolderId) + private Dictionary MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, T destFolderId) { var result = new Dictionary(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var toFolder = folderDao.GetFolder(destFolderId); ErrorIf(toFolder == null, FilesCommonResource.ErrorMassage_FolderNotFound); @@ -1332,14 +1326,14 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList MoveOrCopyItems(ItemList items, string destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) + public ItemList MoveOrCopyItems(ItemList items, T destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) { ItemList result; if (items.Count != 0) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); - result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); + result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); } else { @@ -1348,17 +1342,17 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList DeleteItems(string action, ItemList items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) + public ItemList DeleteItems(string action, ItemList items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return FileOperationsManagerHelper.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); } - public ItemList EmptyTrash() + public ItemList EmptyTrash() { - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var trashId = folderDao.GetFolderIDTrash(true); var foldersId = folderDao.GetFolders(trashId).Select(f => f.ID).ToList(); var filesId = fileDao.GetFiles(trashId).ToList(); @@ -1366,22 +1360,15 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Delete(foldersId, filesId, false, true, false, GetHttpHeaders()); } - public ItemList CheckConversion(ItemList> filesInfoJSON) + public ItemList CheckConversion(ItemList> filesInfoJSON) { if (filesInfoJSON == null || filesInfoJSON.Count == 0) return new ItemList(); - var fileDao = GetFileDao(); - var files = new List>(); + var fileDao = GetFileDao(); + var files = new List, bool>>(); foreach (var fileInfo in filesInfoJSON) { - object fileId; - - var fileIdAsString = fileInfo[0]; - - if (int.TryParse(fileIdAsString, out var fileIdAsInt)) - fileId = fileIdAsInt; - else - fileId = fileIdAsString; + var fileId = (T)Convert.ChangeType(fileInfo[0], typeof(T)); var file = int.TryParse(fileInfo[1], out var version) && version > 0 ? fileDao.GetFile(fileId, version) @@ -1389,11 +1376,11 @@ namespace ASC.Web.Files.Services.WCFService if (file == null) { - var newFile = ServiceProvider.GetService(); + var newFile = ServiceProvider.GetService>(); newFile.ID = fileId; newFile.Version = version; - files.Add(new KeyValuePair(newFile, true)); + files.Add(new KeyValuePair, bool>(newFile, true)); continue; } @@ -1412,7 +1399,7 @@ namespace ASC.Web.Files.Services.WCFService } } - files.Add(new KeyValuePair(file, false)); + files.Add(new KeyValuePair, bool>(file, false)); } var results = FileConverter.GetStatus(files).ToList(); @@ -1420,7 +1407,7 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(results); } - public void ReassignStorage(Guid userFromId, Guid userToId) + public void ReassignStorage(Guid userFromId, Guid userToId) { //check current user have access ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException); @@ -1448,8 +1435,8 @@ namespace ASC.Web.Files.Services.WCFService } } - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); if (!userFrom.IsVisitor(UserManager)) { @@ -1459,7 +1446,7 @@ namespace ASC.Web.Files.Services.WCFService { //create folder with name userFrom in folder userTo var folderIdToMy = folderDao.GetFolderIDUser(true, userTo.ID); - var newFolder = ServiceProvider.GetService(); + var newFolder = ServiceProvider.GetService>(); newFolder.Title = string.Format(CustomNamingPeople.Substitute("TitleDeletedUserFolder"), userFrom.DisplayUserName(false, DisplayUserSettingsHelper)); newFolder.ParentFolderID = folderIdToMy; @@ -1472,10 +1459,10 @@ namespace ASC.Web.Files.Services.WCFService } } - EntryManager.ReassignItems(GlobalFolderHelper.FolderCommon, userFrom.ID, userTo.ID, folderDao, fileDao); + EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userFrom.ID, userTo.ID, folderDao, fileDao); } - public void DeleteStorage(Guid userId) + public void DeleteStorage(Guid userId) { //check current user have access ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException); @@ -1496,15 +1483,15 @@ namespace ASC.Web.Files.Services.WCFService } } - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); //delete all markAsNew - var rootFoldersId = new List + var rootFoldersId = new List { - GlobalFolderHelper.FolderShare, - GlobalFolderHelper.FolderCommon, - GlobalFolderHelper.FolderProjects, + GlobalFolderHelper.GetFolderShare(), + GlobalFolderHelper.GetFolderCommon(), + GlobalFolderHelper.GetFolderProjects(), }; var folderIdFromMy = folderDao.GetFolderIDUser(false, userId); @@ -1533,12 +1520,12 @@ namespace ASC.Web.Files.Services.WCFService var folderIdFromTrash = folderDao.GetFolderIDTrash(false, userId); if (!Equals(folderIdFromTrash, 0)) { - EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao); + EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao); folderDao.DeleteFolder(folderIdFromTrash); GlobalFolderHelper.FolderTrash = userId; } - EntryManager.ReassignItems(GlobalFolderHelper.FolderCommon, userId, AuthContext.CurrentAccount.ID, folderDao, fileDao); + EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userId, AuthContext.CurrentAccount.ID, folderDao, fileDao); } public ItemList GetSharedInfo(ItemList objectIds) @@ -1551,16 +1538,16 @@ namespace ASC.Web.Files.Services.WCFService return FileSharing.GetSharedInfoShort(objectId); } - public ItemList SetAceObject(AceCollection aceCollection, bool notify) + public ItemList SetAceObject(AceCollection aceCollection, bool notify) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var folderDao = GetFolderDao(); var result = new ItemList(); foreach (var objectId in aceCollection.Entries) { Debug.Assert(objectId != null, "objectId != null"); var entryType = objectId.StartsWith("file_") ? FileEntryType.File : FileEntryType.Folder; - var entryId = objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length); + var entryId = (T)Convert.ChangeType(objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length), typeof(T)); var entry = entryType == FileEntryType.File ? (FileEntry)fileDao.GetFile(entryId) : (FileEntry)folderDao.GetFolder(entryId); @@ -1589,25 +1576,25 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public void RemoveAce(ItemList items) + public void RemoveAce(ItemList items) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); var entries = new List(); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); entries.AddRange(filesId.Select(fileId => fileDao.GetFile(fileId))); entries.AddRange(foldersId.Select(folderDao.GetFolder)); FileSharingAceHelper.RemoveAce(entries); } - public string GetShortenLink(string fileId) + public string GetShortenLink(T fileId) { - File file; - var fileDao = GetFileDao(); + File file; + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); var shareLink = FileShareLink.GetLink(file); @@ -1622,10 +1609,10 @@ namespace ASC.Web.Files.Services.WCFService } } - public bool SetAceLink(string fileId, FileShare share) + public bool SetAceLink(T fileId, FileShare share) { FileEntry file; - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); var aces = new List { @@ -1655,13 +1642,13 @@ namespace ASC.Web.Files.Services.WCFService return securityDao.IsShared(file.ID, FileEntryType.File); } - public ItemList SharedUsers(string fileId) + public ItemList SharedUsers(T fileId) { if (!AuthContext.IsAuthenticated || CoreBaseSettings.Personal) return null; FileEntry file; - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); @@ -1693,12 +1680,12 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(users); } - public ItemList SendEditorNotify(string fileId, MentionMessageWrapper mentionMessage) + public ItemList SendEditorNotify(T fileId, MentionMessageWrapper mentionMessage) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); - File file; - var fileDao = GetFileDao(); + File file; + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); @@ -1813,12 +1800,12 @@ namespace ASC.Web.Files.Services.WCFService //return new ItemList(accounts); } - public ItemList ChangeOwner(ItemList items, Guid userId) + public ItemList ChangeOwner(ItemList items, Guid userId) { var userInfo = UserManager.GetUsers(userId); ErrorIf(Equals(userInfo, Constants.LostUser) || userInfo.IsVisitor(UserManager), FilesCommonResource.ErrorMassage_ChangeOwner); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); var entries = new List(); @@ -1847,7 +1834,7 @@ namespace ASC.Web.Files.Services.WCFService entries.Add(newFolder); } - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var files = fileDao.GetFiles(filesId.ToArray()); foreach (var file in files) @@ -1861,7 +1848,7 @@ namespace ASC.Web.Files.Services.WCFService var newFile = file; if (file.CreateBy != userInfo.ID) { - newFile = ServiceProvider.GetService(); + newFile = ServiceProvider.GetService>(); newFile.ID = file.ID; newFile.Version = file.Version + 1; newFile.VersionGroup = file.VersionGroup + 1; @@ -1957,9 +1944,14 @@ namespace ASC.Web.Files.Services.WCFService return DaoFactory.FolderDao; } - private IFileDao GetFileDao() + private IFolderDao GetFolderDao() { - return DaoFactory.FileDao; + return DaoFactory.GetFolderDao(); + } + + private IFileDao GetFileDao() + { + return DaoFactory.GetFileDao(); } private ITagDao GetTagDao() @@ -1982,15 +1974,15 @@ namespace ASC.Web.Files.Services.WCFService return DaoFactory.SecurityDao; } - private static void ParseArrayItems(IEnumerable data, out List foldersId, out List filesId) + private static void ParseArrayItems(IEnumerable data, out List foldersId, out List filesId) { //TODO:!!!!Fix - foldersId = new List(); - filesId = new List(); + foldersId = new List(); + filesId = new List(); foreach (var id in data) { - if (id.StartsWith("file_")) filesId.Add(id.Substring("file_".Length)); - if (id.StartsWith("folder_")) foldersId.Add(id.Substring("folder_".Length)); + if (id.StartsWith("file_")) filesId.Add((T)Convert.ChangeType(id.Substring("file_".Length), typeof(T))); + if (id.StartsWith("folder_")) foldersId.Add((T)Convert.ChangeType(id.Substring("folder_".Length), typeof(T))); } } @@ -2044,7 +2036,7 @@ namespace ASC.Web.Files.Services.WCFService public static DIHelper AddFileStorageService(this DIHelper services) { services.TryAddScoped(); - services.TryAddScoped(); + //services.TryAddScoped(); return services .AddGlobalService() .AddGlobalStoreService() @@ -2085,9 +2077,9 @@ namespace ASC.Web.Files.Services.WCFService } } - public class FileModel + public class FileModel { - public string ParentId { get; set; } + public T ParentId { get; set; } public string Title { get; set; } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Security/FileSecurity.cs b/products/ASC.Files/Server/Core/Security/FileSecurity.cs index 0ee74b380f..2f7aa81ea9 100644 --- a/products/ASC.Files/Server/Core/Security/FileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/FileSecurity.cs @@ -290,11 +290,21 @@ namespace ASC.Files.Core.Security return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast(); } + public IEnumerable> FilterRead(IEnumerable> entries) + { + return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); + } + public IEnumerable FilterRead(IEnumerable entries) { return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast(); } + public IEnumerable> FilterRead(IEnumerable> entries) + { + return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); + } + public IEnumerable FilterEdit(IEnumerable entries) { return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast(); diff --git a/products/ASC.Files/Server/Helpers/Global.cs b/products/ASC.Files/Server/Helpers/Global.cs index 86b740ff7f..ec118be4db 100644 --- a/products/ASC.Files/Server/Helpers/Global.cs +++ b/products/ASC.Files/Server/Helpers/Global.cs @@ -299,6 +299,23 @@ namespace ASC.Web.Files.Classes return result; } + public T GetFolderProjects(IDaoFactory daoFactory) + { + if (CoreBaseSettings.Personal) return default; + + if (WebItemManager[WebItemManager.ProjectsProductID].IsDisabled(WebItemSecurity, AuthContext)) return default; + + var folderDao = daoFactory.GetFolderDao(); + if (!ProjectsRootFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var result)) + { + result = folderDao.GetFolderIDProjects(true); + + ProjectsRootFolderCache[TenantManager.GetCurrentTenant().TenantId] = result; + } + + return (T)result; + } + internal static readonly IDictionary UserRootFolderCache = new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ @@ -339,6 +356,18 @@ namespace ASC.Web.Files.Classes } return commonFolderId; } + public T GetFolderCommon(FileMarker fileMarker, IDaoFactory daoFactory) + { + if (CoreBaseSettings.Personal) return default; + + if (!CommonFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var commonFolderId)) + { + commonFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, false); + if (!Equals(commonFolderId, 0)) + CommonFolderCache[TenantManager.GetCurrentTenant().TenantId] = commonFolderId; + } + return (T)commonFolderId; + } internal static readonly IDictionary ShareFolderCache = new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ @@ -359,6 +388,22 @@ namespace ASC.Web.Files.Classes return sharedFolderId; } + public T GetFolderShare(IFolderDao folderDao) + { + if (CoreBaseSettings.Personal) return default; + if (IsOutsider) return default; + + if (!ShareFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var sharedFolderId)) + { + sharedFolderId = folderDao.GetFolderIDShare(true); + + if (!sharedFolderId.Equals(default)) + ShareFolderCache[TenantManager.GetCurrentTenant().TenantId] = sharedFolderId; + } + + return (T)sharedFolderId; + } + internal static readonly IDictionary TrashFolderCache = new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ @@ -382,6 +427,42 @@ namespace ASC.Web.Files.Classes TrashFolderCache.Remove(cacheKey); } + private T GetFolderIdAndProccessFirstVisit(FileMarker fileMarker, IDaoFactory daoFactory, bool my) + { + var folderDao = daoFactory.GetFolderDao(); + var fileDao = daoFactory.GetFileDao(); + + var id = my ? folderDao.GetFolderIDUser(false) : folderDao.GetFolderIDCommon(false); + + if (Equals(id, 0)) //TODO: think about 'null' + { + id = my ? folderDao.GetFolderIDUser(true) : folderDao.GetFolderIDCommon(true); + + //Copy start document + if (AdditionalWhiteLabelSettings.Instance(SettingsManager).StartDocsEnabled) + { + try + { + var storeTemplate = GlobalStore.GetStoreTemplate(); + + var culture = my ? UserManager.GetUsers(AuthContext.CurrentAccount.ID).GetCulture() : TenantManager.GetCurrentTenant().GetCulture(); + var path = FileConstant.StartDocPath + culture + "/"; + + if (!storeTemplate.IsDirectory(path)) + path = FileConstant.StartDocPath + "default/"; + path += my ? "my/" : "corporate/"; + + SaveStartDocument(fileMarker, folderDao, fileDao, id, path, storeTemplate); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + } + + return id; + } private object GetFolderIdAndProccessFirstVisit(FileMarker fileMarker, IDaoFactory daoFactory, bool my) { var folderDao = daoFactory.FolderDao; @@ -438,6 +519,25 @@ namespace ASC.Web.Files.Classes } } + private void SaveStartDocument(FileMarker fileMarker, IFolderDao folderDao, IFileDao fileDao, T folderId, string path, IDataStore storeTemplate) + { + foreach (var file in storeTemplate.ListFilesRelative("", path, "*", false)) + { + SaveFile(fileMarker, fileDao, folderId, path + file, storeTemplate); + } + + foreach (var folderName in storeTemplate.ListDirectoriesRelative(path, false)) + { + var folder = ServiceProvider.GetService>(); + folder.Title = folderName; + folder.ParentFolderID = folderId; + + var subFolderId = folderDao.SaveFolder(folder); + + SaveStartDocument(fileMarker, folderDao, fileDao, subFolderId, path + folderName + "/", storeTemplate); + } + } + private void SaveFile(FileMarker fileMarker, IFileDao fileDao, object folder, string filePath, IDataStore storeTemp) { using var stream = storeTemp.GetReadStream("", filePath); @@ -461,6 +561,31 @@ namespace ASC.Web.Files.Classes Logger.Error(ex); } } + + private void SaveFile(FileMarker fileMarker, IFileDao fileDao, T folder, string filePath, IDataStore storeTemp) + { + using var stream = storeTemp.GetReadStream("", filePath); + var fileName = Path.GetFileName(filePath); + var file = ServiceProvider.GetService>(); + + file.Title = fileName; + file.ContentLength = stream.CanSeek ? stream.Length : storeTemp.GetFileSize("", filePath); + file.FolderID = folder; + file.Comment = FilesCommonResource.CommentCreate; + + stream.Position = 0; + try + { + file = fileDao.SaveFile(file, stream); + + fileMarker.MarkAsNew(file); + } + catch (Exception ex) + { + Logger.Error(ex); + } + } + public bool IsOutsider { get { return UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsOutsider(UserManager); } @@ -487,6 +612,11 @@ namespace ASC.Web.Files.Classes return GlobalFolder.GetFolderProjects(DaoFactory); } } + public T GetFolderProjects() + { + return GlobalFolder.GetFolderProjects(DaoFactory); + } + public object FolderCommon { get @@ -495,6 +625,11 @@ namespace ASC.Web.Files.Classes } } + public T GetFolderCommon() + { + return GlobalFolder.GetFolderCommon(FileMarker, DaoFactory); + } + public object FolderMy { get @@ -515,6 +650,11 @@ namespace ASC.Web.Files.Classes } } + public T GetFolderShare() + { + return GlobalFolder.GetFolderShare(DaoFactory.GetFolderDao()); + } + public object FolderTrash { get diff --git a/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs b/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs index 3913b782e4..0d21fd68e1 100644 --- a/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs +++ b/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs @@ -118,7 +118,7 @@ namespace ASC.Web.Files.HttpHandlers switch (request.Type(InstanceCrypto)) { case ChunkedRequestType.Abort: - FileUploader.AbortUpload(request.UploadId); + FileUploader.AbortUpload(request.UploadId); WriteSuccess(context, null); return; @@ -128,7 +128,7 @@ namespace ASC.Web.Files.HttpHandlers return; case ChunkedRequestType.Upload: - var resumedSession = FileUploader.UploadChunk(request.UploadId, request.ChunkStream, request.ChunkSize); + var resumedSession = FileUploader.UploadChunk(request.UploadId, request.ChunkStream, request.ChunkSize); if (resumedSession.BytesUploaded == resumedSession.BytesTotal) { @@ -174,7 +174,7 @@ namespace ASC.Web.Files.HttpHandlers if (!string.IsNullOrEmpty(request.UploadId)) { - var uploadSession = ChunkedUploadSessionHolder.GetSession(request.UploadId); + var uploadSession = ChunkedUploadSessionHolder.GetSession(request.UploadId); if (uploadSession != null) { TenantManager.SetCurrentTenant(uploadSession.TenantId); diff --git a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs index 2c06b23be8..b6465ebaca 100644 --- a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs @@ -38,7 +38,6 @@ using ASC.Common.Logging; using ASC.Common.Web; using ASC.Core; using ASC.Files.Core; -using ASC.Files.Core.Data; using ASC.Files.Core.Security; using ASC.Files.Resources; using ASC.MessagingSystem; @@ -266,14 +265,27 @@ namespace ASC.Web.Files } private void DownloadFile(HttpContext context) + { + var q = context.Request.Query[FilesLinkUtility.FileId]; + + if (int.TryParse(q, out var id)) + { + DownloadFile(context, id); + } + else + { + DownloadFile(context, q); + } + } + + private void DownloadFile(HttpContext context, T id) { var flushed = false; try { - var id = context.Request.Query[FilesLinkUtility.FileId]; var doc = context.Request.Query[FilesLinkUtility.DocShareKey].FirstOrDefault() ?? ""; - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var readLink = FileShareLink.Check(doc, true, fileDao, out var file); if (!readLink && file == null) { @@ -352,7 +364,7 @@ namespace ASC.Web.Files && FFmpegService.IsConvertable(ext)) { const string mp4Name = "content.mp4"; - var mp4Path = FileDao.GetUniqFilePath(file, mp4Name); + var mp4Path = fileDao.GetUniqFilePath(file, mp4Name); var store = GlobalStore.GetStore(); if (!store.IsFile(mp4Path)) { diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index 51f023db7e..3c4cfe1541 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -39,13 +39,13 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Web.Files.Services.WCFService.FileOperations { - internal class FileDeleteOperationData : FileOperationData + internal class FileDeleteOperationData : FileOperationData { public bool IgnoreException { get; } public bool Immediately { get; } public Dictionary Headers { get; } - public FileDeleteOperationData(List folders, List files, Tenant tenant, + public FileDeleteOperationData(List folders, List files, Tenant tenant, bool holdResult = true, bool ignoreException = false, bool immediately = false, Dictionary headers = null) : base(folders, files, tenant, holdResult) { @@ -55,9 +55,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - class FileDeleteOperation : FileOperation + class FileDeleteOperation : FileOperation, T> { - private object _trashId; + private T _trashId; private readonly bool _ignoreException; private readonly bool _immediately; private readonly Dictionary _headers; @@ -68,7 +68,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - public FileDeleteOperation(IServiceProvider serviceProvider, FileDeleteOperationData fileOperationData) + public FileDeleteOperation(IServiceProvider serviceProvider, FileDeleteOperationData fileOperationData) : base(serviceProvider, fileOperationData) { _ignoreException = fileOperationData.IgnoreException; @@ -99,7 +99,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations DeleteFolders(Folders, scope); } - private void DeleteFolders(IEnumerable folderIds, IServiceScope scope) + private void DeleteFolders(IEnumerable folderIds, IServiceScope scope) { var fileMarker = scope.ServiceProvider.GetService(); var filesMessageService = scope.ServiceProvider.GetService(); @@ -109,7 +109,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations CancellationToken.ThrowIfCancellationRequested(); var folder = FolderDao.GetFolder(folderId); - object canCalculate = null; + T canCalculate = default; if (folder == null) { Error = FilesCommonResource.ErrorMassage_FolderNotFound; @@ -120,13 +120,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } else if (!_ignoreException && !FilesSecurity.CanDelete(folder)) { - canCalculate = FolderDao.CanCalculateSubitems(folderId) ? null : folderId; + canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId; Error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder; } else { - canCalculate = FolderDao.CanCalculateSubitems(folderId) ? null : folderId; + canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId; fileMarker.RemoveMarkAsNewForAll(folder); if (folder.ProviderEntry && folder.ID.Equals(folder.RootFolderId)) @@ -142,7 +142,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations else { var immediately = _immediately || !FolderDao.UseTrashForRemove(folder); - if (immediately && FolderDao.UseRecursiveOperation(folder.ID, null)) + if (immediately && FolderDao.UseRecursiveOperation(folder.ID, default)) { DeleteFiles(FileDao.GetFiles(folder.ID), scope); DeleteFolders(FolderDao.GetFolders(folder.ID).Select(f => f.ID).ToList(), scope); @@ -184,7 +184,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - private void DeleteFiles(IEnumerable fileIds, IServiceScope scope) + private void DeleteFiles(IEnumerable fileIds, IServiceScope scope) { var fileMarker = scope.ServiceProvider.GetService(); var filesMessageService = scope.ServiceProvider.GetService(); @@ -225,7 +225,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } ProcessedFile(fileId); } - ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? null : fileId); + ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? default : fileId); } } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs index 94764f3a35..3bf68ea864 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs @@ -47,16 +47,14 @@ using Ionic.Zip; using Microsoft.Extensions.DependencyInjection; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Services.WCFService.FileOperations { - internal class FileDownloadOperationData : FileOperationData + internal class FileDownloadOperationData : FileOperationData { - public Dictionary FilesDownload { get; } + public Dictionary FilesDownload { get; } public Dictionary Headers { get; } - public FileDownloadOperationData(Dictionary folders, Dictionary files, Tenant tenant, Dictionary headers, bool holdResult = true) + public FileDownloadOperationData(Dictionary folders, Dictionary files, Tenant tenant, Dictionary headers, bool holdResult = true) : base(folders.Select(f => f.Key).ToList(), files.Select(f => f.Key).ToList(), tenant, holdResult) { FilesDownload = files; @@ -64,9 +62,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - class FileDownloadOperation : FileOperation + class FileDownloadOperation : FileOperation, T> { - private readonly Dictionary files; + private readonly Dictionary files; private readonly Dictionary headers; public override FileOperationType OperationType @@ -75,7 +73,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData fileDownloadOperationData) + public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData fileDownloadOperationData) : base(serviceProvider, fileDownloadOperationData) { files = fileDownloadOperationData.FilesDownload; @@ -114,16 +112,16 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - private ItemNameValueCollection ExecPathFromFile(IServiceScope scope, File file, string path) + private ItemNameValueCollection ExecPathFromFile(IServiceScope scope, File file, string path) { var fileMarker = scope.ServiceProvider.GetService(); fileMarker.RemoveMarkAsNew(file); var title = file.Title; - if (files.ContainsKey(file.ID.ToString())) + if (files.ContainsKey(file.ID)) { - var convertToExt = files[file.ID.ToString()]; + var convertToExt = files[file.ID]; if (!string.IsNullOrEmpty(convertToExt)) { @@ -131,16 +129,16 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - var entriesPathId = new ItemNameValueCollection(); - entriesPathId.Add(path + title, file.ID.ToString()); + var entriesPathId = new ItemNameValueCollection(); + entriesPathId.Add(path + title, file.ID); return entriesPathId; } - private ItemNameValueCollection GetEntriesPathId(IServiceScope scope) + private ItemNameValueCollection GetEntriesPathId(IServiceScope scope) { var fileMarker = scope.ServiceProvider.GetService(); - var entriesPathId = new ItemNameValueCollection(); + var entriesPathId = new ItemNameValueCollection(); if (0 < Files.Count) { var files = FileDao.GetFiles(Files.ToArray()); @@ -158,13 +156,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return entriesPathId; } - private ItemNameValueCollection GetFilesInFolders(IServiceScope scope, IEnumerable folderIds, string path) + private ItemNameValueCollection GetFilesInFolders(IServiceScope scope, IEnumerable folderIds, string path) { var fileMarker = scope.ServiceProvider.GetService(); CancellationToken.ThrowIfCancellationRequested(); - var entriesPathId = new ItemNameValueCollection(); + var entriesPathId = new ItemNameValueCollection(); foreach (var folderId in folderIds) { CancellationToken.ThrowIfCancellationRequested(); @@ -183,7 +181,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations nestedFolders = FilesSecurity.FilterRead(nestedFolders).ToList(); if (files.Count == 0 && nestedFolders.Count == 0) { - entriesPathId.Add(folderPath, string.Empty); + entriesPathId.Add(folderPath, default(T)); } var filesInFolder = GetFilesInFolders(scope, nestedFolders.ConvertAll(f => f.ID), folderPath); @@ -192,7 +190,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return entriesPathId; } - private Stream CompressToZip(IServiceScope scope, ItemNameValueCollection entriesPathId) + private Stream CompressToZip(IServiceScope scope, ItemNameValueCollection entriesPathId) { var setupInfo = scope.ServiceProvider.GetService(); var fileConverter = scope.ServiceProvider.GetService(); @@ -219,10 +217,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations var newtitle = path; - File file = null; + File file = null; var convertToExt = string.Empty; - if (!string.IsNullOrEmpty(entryId)) + if (!entryId.Equals(default(T))) { FileDao.InvalidateCache(entryId); file = FileDao.GetFile(entryId); @@ -239,9 +237,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations continue; } - if (files.ContainsKey(file.ID.ToString())) + if (files.ContainsKey(file.ID)) { - convertToExt = files[file.ID.ToString()]; + convertToExt = files[file.ID]; if (!string.IsNullOrEmpty(convertToExt)) { newtitle = FileUtility.ReplaceFileExtension(path, convertToExt); @@ -253,7 +251,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { var suffix = " (" + counter + ")"; - if (!string.IsNullOrEmpty(entryId)) + if (!entryId.Equals(default(T))) { newtitle = 0 < newtitle.IndexOf('.') ? newtitle.Insert(newtitle.LastIndexOf('.'), suffix) : newtitle + suffix; } @@ -265,7 +263,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations zip.PutNextEntry(newtitle); - if (!string.IsNullOrEmpty(entryId) && file != null) + if (!entryId.Equals(default(T)) && file != null) { try { @@ -307,7 +305,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return stream; } - private void ReplaceLongPath(ItemNameValueCollection entriesPathId) + private void ReplaceLongPath(ItemNameValueCollection entriesPathId) { foreach (var path in new List(entriesPathId.AllKeys)) { @@ -324,9 +322,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - class ItemNameValueCollection + class ItemNameValueCollection { - private readonly Dictionary> dic = new Dictionary>(); + private readonly Dictionary> dic = new Dictionary>(); public IEnumerable AllKeys @@ -334,7 +332,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations get { return dic.Keys; } } - public IEnumerable this[string name] + public IEnumerable this[string name] { get { return dic[name].ToArray(); } } @@ -344,16 +342,16 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations get { return dic.Count; } } - public void Add(string name, string value) + public void Add(string name, T value) { if (!dic.ContainsKey(name)) { - dic.Add(name, new List()); + dic.Add(name, new List()); } dic[name].Add(value); } - public void Add(ItemNameValueCollection collection) + public void Add(ItemNameValueCollection collection) { foreach (var key in collection.AllKeys) { @@ -364,11 +362,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - public void Add(string name, IEnumerable values) + public void Add(string name, IEnumerable values) { if (!dic.ContainsKey(name)) { - dic.Add(name, new List()); + dic.Add(name, new List()); } dic[name].AddRange(values); } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs index 48aeebf12c..fa47880d72 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs @@ -38,14 +38,14 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Web.Files.Services.WCFService.FileOperations { - class FileMarkAsReadOperationData : FileOperationData + class FileMarkAsReadOperationData : FileOperationData { - public FileMarkAsReadOperationData(List folders, List files, Tenant tenant, bool holdResult = true) : base(folders, files, tenant, holdResult) + public FileMarkAsReadOperationData(List folders, List files, Tenant tenant, bool holdResult = true) : base(folders, files, tenant, holdResult) { } } - class FileMarkAsReadOperation : FileOperation + class FileMarkAsReadOperation : FileOperation, T> { public override FileOperationType OperationType { @@ -53,7 +53,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - public FileMarkAsReadOperation(IServiceProvider serviceProvider, FileMarkAsReadOperationData fileOperationData) + public FileMarkAsReadOperation(IServiceProvider serviceProvider, FileMarkAsReadOperationData fileOperationData) : base(serviceProvider, fileOperationData) { } @@ -84,11 +84,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (x.FileEntryType == FileEntryType.File) { - ProcessedFile(x.ID.ToString()); + ProcessedFile(((File)x).ID); } else { - ProcessedFolder(x.ID.ToString()); + ProcessedFolder(((Folder)x).ID); } ProgressStep(); }); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index dc45bfa094..8d54bc20d3 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -25,7 +25,6 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; @@ -42,14 +41,14 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Web.Files.Services.WCFService.FileOperations { - internal class FileMoveCopyOperationData : FileOperationData + internal class FileMoveCopyOperationData : FileOperationData { - public string ToFolderId { get; } + public T ToFolderId { get; } public bool Copy { get; } public FileConflictResolveType ResolveType { get; } public Dictionary Headers { get; } - public FileMoveCopyOperationData(List folders, List files, Tenant tenant, string toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary headers = null) + public FileMoveCopyOperationData(List folders, List files, Tenant tenant, T toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary headers = null) : base(folders, files, tenant, holdResult) { ToFolderId = toFolderId; @@ -59,9 +58,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - class FileMoveCopyOperation : FileOperation + class FileMoveCopyOperation : FileOperation, T> { - private readonly string _toFolderId; + private readonly T _toFolderId; private readonly bool _copy; private readonly FileConflictResolveType _resolveType; private readonly List _needToMark = new List(); @@ -73,7 +72,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations get { return _copy ? FileOperationType.Copy : FileOperationType.Move; } } - public FileMoveCopyOperation(IServiceProvider serviceProvider, FileMoveCopyOperationData data) + public FileMoveCopyOperation(IServiceProvider serviceProvider, FileMoveCopyOperationData data) : base(serviceProvider, data) { _toFolderId = data.ToFolderId; @@ -94,7 +93,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (toFolder == null) return; if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); - if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID.ToString()))) + if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID))) { Error = FilesCommonResource.ErrorMassage_FolderCopyError; return; @@ -115,7 +114,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); } - private void MoveOrCopyFolders(IServiceScope scope, ICollection folderIds, Folder toFolder, bool copy) + private void MoveOrCopyFolders(IServiceScope scope, List folderIds, Folder toFolder, bool copy) { if (folderIds.Count == 0) return; @@ -137,13 +136,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFolder; } - else if (!Equals((folder.ParentFolderID ?? string.Empty).ToString(), toFolderId.ToString()) || _resolveType == FileConflictResolveType.Duplicate) + else if (!Equals((folder.ParentFolderID ?? default).ToString(), toFolderId.ToString()) || _resolveType == FileConflictResolveType.Duplicate) { try { //if destination folder contains folder with same name then merge folders var conflictFolder = FolderDao.GetFolder(folder.Title, toFolderId); - Folder newFolder; + Folder newFolder; if (copy || conflictFolder != null) { @@ -193,7 +192,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { if (conflictFolder != null) { - object newFolderId; + T newFolderId; if (copy) { newFolder = FolderDao.CopyFolder(folder.ID, toFolderId, CancellationToken); @@ -270,11 +269,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Logger.Error(Error, ex); } } - ProgressStep(FolderDao.CanCalculateSubitems(folderId) ? null : folderId); + ProgressStep(FolderDao.CanCalculateSubitems(folderId) ? default : folderId); } } - private void MoveOrCopyFiles(IServiceScope scope, ICollection fileIds, Folder toFolder, bool copy) + private void MoveOrCopyFiles(IServiceScope scope, List fileIds, Folder toFolder, bool copy) { if (fileIds.Count == 0) return; @@ -313,7 +312,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations : FileDao.GetFile(toFolderId, file.Title); if (conflict == null) { - File newFile = null; + File newFile = null; if (copy) { try @@ -451,7 +450,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Logger.Error(Error, ex); } } - ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? null : fileId); + ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? default : fileId); } } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index 549ced883c..e04e77381c 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -48,20 +48,20 @@ using Microsoft.Extensions.Options; namespace ASC.Web.Files.Services.WCFService.FileOperations { - abstract class FileOperationData + abstract class FileOperationData { - public List Folders { get; private set; } + public List Folders { get; private set; } - public List Files { get; private set; } + public List Files { get; private set; } public Tenant Tenant { get; } public bool HoldResult { get; private set; } - protected FileOperationData(List folders, List files, Tenant tenant, bool holdResult = true) + protected FileOperationData(List folders, List files, Tenant tenant, bool holdResult = true) { - Folders = folders ?? new List(); - Files = files ?? new List(); + Folders = folders ?? new List(); + Files = files ?? new List(); Tenant = tenant; HoldResult = holdResult; } @@ -81,7 +81,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public const string HOLD = "Hold"; } - abstract class FileOperation where T : FileOperationData + abstract class FileOperation where T : FileOperationData { private readonly IPrincipal principal; private readonly string culture; @@ -100,9 +100,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected FileSecurity FilesSecurity { get; private set; } - protected IFolderDao FolderDao { get; private set; } + protected IFolderDao FolderDao { get; private set; } - protected IFileDao FileDao { get; private set; } + protected IFileDao FileDao { get; private set; } protected ITagDao TagDao { get; private set; } @@ -112,9 +112,9 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected CancellationToken CancellationToken { get; private set; } - protected List Folders { get; private set; } + protected List Folders { get; private set; } - protected List Files { get; private set; } + protected List Files { get; private set; } protected bool HoldResult { get; private set; } @@ -152,8 +152,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture); - FolderDao = daoFactory.FolderDao; - FileDao = daoFactory.FileDao; + FolderDao = daoFactory.GetFolderDao(); + FileDao = daoFactory.GetFileDao(); TagDao = daoFactory.TagDao; ProviderDao = daoFactory.ProviderDao; FilesSecurity = fileSecurity; @@ -219,7 +219,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return count; } - protected void ProgressStep(object folderId = null, object fileId = null) + protected void ProgressStep(TId folderId = default, TId fileId = default) { if (folderId == null && fileId == null || folderId != null && Folders.Contains(folderId) @@ -230,7 +230,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - protected bool ProcessedFolder(object folderId) + protected bool ProcessedFolder(TId folderId) { successProcessed++; if (Folders.Contains(folderId)) @@ -241,7 +241,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return false; } - protected bool ProcessedFile(object fileId) + protected bool ProcessedFile(TId fileId) { successProcessed++; if (Files.Contains(fileId)) diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index 6e3cfb95fe..a2de8f9497 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -98,13 +98,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - public ItemList MarkAsRead(AuthContext authContext, TenantManager tenantManager, List folderIds, List fileIds) + public ItemList MarkAsRead(AuthContext authContext, TenantManager tenantManager, List folderIds, List fileIds) { - var op = new FileMarkAsReadOperation(ServiceProvider, new FileMarkAsReadOperationData(folderIds, fileIds, tenantManager.GetCurrentTenant())); + var op = new FileMarkAsReadOperation(ServiceProvider, new FileMarkAsReadOperationData(folderIds, fileIds, tenantManager.GetCurrentTenant())); return QueueTask(authContext, op); } - public ItemList Download(AuthContext authContext, TenantManager tenantManager, Dictionary folders, Dictionary files, Dictionary headers) + public ItemList Download(AuthContext authContext, TenantManager tenantManager, Dictionary folders, Dictionary files, Dictionary headers) { var operations = tasks.GetTasks() .Where(t => t.GetProperty(FileOperation.OWNER) == authContext.CurrentAccount.ID) @@ -115,24 +115,24 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations throw new InvalidOperationException(FilesCommonResource.ErrorMassage_ManyDownloads); } - var op = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders, files, tenantManager.GetCurrentTenant(), headers)); + var op = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders, files, tenantManager.GetCurrentTenant(), headers)); return QueueTask(authContext, op); } - public ItemList MoveOrCopy(AuthContext authContext, TenantManager tenantManager, List folders, List files, string destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) + public ItemList MoveOrCopy(AuthContext authContext, TenantManager tenantManager, List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) { - var op = new FileMoveCopyOperation(ServiceProvider, new FileMoveCopyOperationData(folders, files, tenantManager.GetCurrentTenant(), destFolderId, copy, resolveType, holdResult, headers)); + var op = new FileMoveCopyOperation(ServiceProvider, new FileMoveCopyOperationData(folders, files, tenantManager.GetCurrentTenant(), destFolderId, copy, resolveType, holdResult, headers)); return QueueTask(authContext, op); } - public ItemList Delete(AuthContext authContext, TenantManager tenantManager, List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + public ItemList Delete(AuthContext authContext, TenantManager tenantManager, List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) { - var op = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders, files, tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); + var op = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders, files, tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); return QueueTask(authContext, op); } - private ItemList QueueTask(AuthContext authContext, FileOperation op) where T : FileOperationData + private ItemList QueueTask(AuthContext authContext, FileOperation op) where T : FileOperationData { tasks.QueueTask(op.RunJob, op.GetDistributedTask()); return GetOperationResults(authContext); @@ -157,15 +157,15 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public ItemList GetOperationResults() => FileOperationsManager.GetOperationResults(AuthContext); public ItemList CancelOperations() => FileOperationsManager.CancelOperations(AuthContext); - public ItemList MarkAsRead(List folderIds, List fileIds) + public ItemList MarkAsRead(List folderIds, List fileIds) => FileOperationsManager.MarkAsRead(AuthContext, TenantManager, folderIds, fileIds); - public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) + public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) => FileOperationsManager.Download(AuthContext, TenantManager, folders, files, headers); - public ItemList MoveOrCopy(List folders, List files, string destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) + public ItemList MoveOrCopy(List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) => FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers); - public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) => FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); } diff --git a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs index de1b66a587..fe29ea8805 100644 --- a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs +++ b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs @@ -73,7 +73,7 @@ namespace ASC.Web.Files.Services.WCFService File GetFile(string fileId, int version); - File CreateNewFile(FileModel fileWrapper); + File CreateNewFile(FileModel fileWrapper); File FileRename(string fileId, string title); diff --git a/products/ASC.Files/Server/Utils/ChunkedUploadSessionHolder.cs b/products/ASC.Files/Server/Utils/ChunkedUploadSessionHolder.cs index dd699ca827..a140ac056a 100644 --- a/products/ASC.Files/Server/Utils/ChunkedUploadSessionHolder.cs +++ b/products/ASC.Files/Server/Utils/ChunkedUploadSessionHolder.cs @@ -36,8 +36,6 @@ using ASC.Web.Studio.Core; using Microsoft.Extensions.Options; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Utils { public class ChunkedUploadSessionHolder @@ -65,49 +63,49 @@ namespace ASC.Web.Files.Utils } } - public void StoreSession(ChunkedUploadSession s) + public void StoreSession(ChunkedUploadSession s) { CommonSessionHolder(false).Store(s); } - public void RemoveSession(ChunkedUploadSession s) + public void RemoveSession(ChunkedUploadSession s) { CommonSessionHolder(false).Remove(s); } - public ChunkedUploadSession GetSession(string sessionId) + public ChunkedUploadSession GetSession(string sessionId) { - return (ChunkedUploadSession)CommonSessionHolder(false).Get(sessionId); + return (ChunkedUploadSession)CommonSessionHolder(false).Get(sessionId); } - public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) { - var result = new ChunkedUploadSession(file, contentLength); + var result = new ChunkedUploadSession(file, contentLength); CommonSessionHolder().Init(result); return result; } - public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long length) + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long length) { CommonSessionHolder().UploadChunk(uploadSession, stream, length); } - public void FinalizeUploadSession(ChunkedUploadSession uploadSession) + public void FinalizeUploadSession(ChunkedUploadSession uploadSession) { CommonSessionHolder().Finalize(uploadSession); } - public void Move(ChunkedUploadSession chunkedUploadSession, string newPath) + public void Move(ChunkedUploadSession chunkedUploadSession, string newPath) { CommonSessionHolder().Move(chunkedUploadSession, newPath); } - public void AbortUploadSession(ChunkedUploadSession uploadSession) + public void AbortUploadSession(ChunkedUploadSession uploadSession) { CommonSessionHolder().Abort(uploadSession); } - public Stream UploadSingleChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + public Stream UploadSingleChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) { return CommonSessionHolder().UploadSingleChunk(uploadSession, stream, chunkLength); } diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index 5a33c2dd70..dfa84b57df 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -805,6 +805,146 @@ namespace ASC.Web.Files.Utils return file; } + public File SaveEditing(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null) + { + var newExtension = string.IsNullOrEmpty(fileExtension) + ? FileUtility.GetFileExtension(downloadUri) + : fileExtension; + + var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); + if (app != null) + { + app.SaveFile(fileId.ToString(), newExtension, downloadUri, stream); + return null; + } + + var fileDao = DaoFactory.GetFileDao(); + var editLink = FileShareLink.Check(doc, false, fileDao, out var file); + if (file == null) + { + file = fileDao.GetFile(fileId); + } + + if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); + var fileSecurity = FileSecurity; + if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); + if (checkRight && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); + if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); + + var currentExt = file.ConvertedExtension; + if (string.IsNullOrEmpty(newExtension)) newExtension = FileUtility.GetInternalExtension(file.Title); + + var replaceVersion = false; + if (file.Forcesave != ForcesaveType.None) + { + if (file.Forcesave == ForcesaveType.User && FilesSettingsHelper.StoreForcesave) + { + file.Version++; + } + else + { + replaceVersion = true; + } + } + else + { + if (file.Version != 1) + { + file.VersionGroup++; + } + else + { + var storeTemplate = GlobalStore.GetStoreTemplate(); + + var path = FileConstant.NewDocPath + Thread.CurrentThread.CurrentCulture + "/"; + if (!storeTemplate.IsDirectory(path)) + { + path = FileConstant.NewDocPath + "default/"; + } + path += "new" + FileUtility.GetInternalExtension(file.Title); + + //todo: think about the criteria for saving after creation + if (file.ContentLength != storeTemplate.GetFileSize("", path)) + { + file.VersionGroup++; + } + } + file.Version++; + } + file.Forcesave = forcesave ?? ForcesaveType.None; + + if (string.IsNullOrEmpty(comment)) + comment = FilesCommonResource.CommentEdit; + + file.Encrypted = encrypted; + + file.ConvertedType = FileUtility.GetFileExtension(file.Title) != newExtension ? newExtension : null; + + if (file.ProviderEntry && !newExtension.Equals(currentExt)) + { + if (FileUtility.ExtsConvertible.Keys.Contains(newExtension) + && FileUtility.ExtsConvertible[newExtension].Contains(currentExt)) + { + if (stream != null) + { + downloadUri = PathProvider.GetTempUrl(stream, newExtension); + downloadUri = DocumentServiceConnector.ReplaceCommunityAdress(downloadUri); + } + + var key = DocumentServiceConnector.GenerateRevisionId(downloadUri); + DocumentServiceConnector.GetConvertedUri(downloadUri, newExtension, currentExt, key, null, false, out downloadUri); + + stream = null; + } + else + { + file.ID = default; + file.Title = FileUtility.ReplaceFileExtension(file.Title, newExtension); + } + + file.ConvertedType = null; + } + + using (var tmpStream = new MemoryStream()) + { + if (stream != null) + { + stream.CopyTo(tmpStream); + } + else + { + // hack. http://ubuntuforums.org/showthread.php?t=1841740 + if (WorkContext.IsMono) + { + ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; + } + + var req = (HttpWebRequest)WebRequest.Create(downloadUri); + using (var editedFileStream = new ResponseStream(req.GetResponse())) + { + editedFileStream.CopyTo(tmpStream); + } + } + tmpStream.Position = 0; + + file.ContentLength = tmpStream.Length; + file.Comment = string.IsNullOrEmpty(comment) ? null : comment; + if (replaceVersion) + { + file = fileDao.ReplaceFileVersion(file, tmpStream); + } + else + { + file = fileDao.SaveFile(file, tmpStream); + } + } + + FileMarker.MarkAsNew(file); + FileMarker.RemoveMarkAsNew(file); + return file; + } + public void TrackEditing(string fileId, Guid tabId, Guid userId, string doc, bool editingAlone = false) { bool checkRight; @@ -908,6 +1048,80 @@ namespace ASC.Web.Files.Utils } } + public File UpdateToVersionFile(T fileId, int version, string doc = null, bool checkRight = true) + { + var fileDao = DaoFactory.GetFileDao(); + if (version < 1) throw new ArgumentNullException("version"); + + var editLink = FileShareLink.Check(doc, false, fileDao, out var fromFile); + + if (fromFile == null) + fromFile = fileDao.GetFile(fileId); + + if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); + + if (fromFile.Version != version) + fromFile = fileDao.GetFile(fromFile.ID, Math.Min(fromFile.Version, version)); + + if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); + if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (FileLockedForMe(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); + if (checkRight && FileTracker.IsEditing(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); + if (fromFile.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); + if (fromFile.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); + + var exists = cache.Get(UPDATE_LIST + fileId.ToString()) != null; + if (exists) + { + throw new Exception(FilesCommonResource.ErrorMassage_UpdateEditingFile); + } + else + { + cache.Insert(UPDATE_LIST + fileId.ToString(), fileId.ToString(), TimeSpan.FromMinutes(2)); + } + + try + { + var currFile = fileDao.GetFile(fileId); + var newFile = ServiceProvider.GetService>(); + + newFile.ID = fromFile.ID; + newFile.Version = currFile.Version + 1; + newFile.VersionGroup = currFile.VersionGroup; + newFile.Title = FileUtility.ReplaceFileExtension(currFile.Title, FileUtility.GetFileExtension(fromFile.Title)); + newFile.FileStatus = currFile.FileStatus; + newFile.FolderID = currFile.FolderID; + newFile.CreateBy = currFile.CreateBy; + newFile.CreateOn = currFile.CreateOn; + newFile.ModifiedBy = fromFile.ModifiedBy; + newFile.ModifiedOn = fromFile.ModifiedOn; + newFile.ConvertedType = fromFile.ConvertedType; + newFile.Comment = string.Format(FilesCommonResource.CommentRevert, fromFile.ModifiedOnString); + newFile.Encrypted = fromFile.Encrypted; + + using (var stream = fileDao.GetFileStream(fromFile)) + { + newFile.ContentLength = stream.CanSeek ? stream.Length : fromFile.ContentLength; + newFile = fileDao.SaveFile(newFile, stream); + } + + FileMarker.MarkAsNew(newFile); + + SetFileStatus(newFile); + + return newFile; + } + catch (Exception e) + { + Logger.Error(string.Format("Error on update {0} to version {1}", fileId, version), e); + throw new Exception(e.Message, e); + } + finally + { + cache.Remove(UPDATE_LIST + fromFile.ID); + } + } + public File CompleteVersionFile(object fileId, int version, bool continueVersion, bool checkRight = true) { var fileDao = DaoFactory.FileDao; @@ -949,6 +1163,47 @@ namespace ASC.Web.Files.Utils return lastVersionFile; } + public File CompleteVersionFile(T fileId, int version, bool continueVersion, bool checkRight = true) + { + var fileDao = DaoFactory.GetFileDao(); + var fileVersion = version > 0 +? fileDao.GetFile(fileId, version) +: fileDao.GetFile(fileId); + if (fileVersion == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); + if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (FileLockedForMe(fileVersion.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); + if (fileVersion.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); + if (fileVersion.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); + + var lastVersionFile = fileDao.GetFile(fileVersion.ID); + + if (continueVersion) + { + if (lastVersionFile.VersionGroup > 1) + { + fileDao.ContinueVersion(fileVersion.ID, fileVersion.Version); + lastVersionFile.VersionGroup--; + } + } + else + { + if (!FileTracker.IsEditing(lastVersionFile.ID)) + { + if (fileVersion.Version == lastVersionFile.Version) + { + lastVersionFile = UpdateToVersionFile(fileVersion.ID, fileVersion.Version, null, checkRight); + } + + fileDao.CompleteVersion(fileVersion.ID, fileVersion.Version); + lastVersionFile.VersionGroup++; + } + } + + SetFileStatus(lastVersionFile); + + return lastVersionFile; + } + public bool FileRename(object fileId, string title, out File file) { var fileDao = DaoFactory.FileDao; @@ -1009,6 +1264,24 @@ namespace ASC.Web.Files.Utils } } + public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao fileDao) + { + var folders = folderDao.GetFolders(parentId); + foreach (var folder in folders) + { + DeleteSubitems(folder.ID, folderDao, fileDao); + + Logger.InfoFormat("Delete folder {0} in {1}", folder.ID, parentId); + folderDao.DeleteFolder(folder.ID); + } + + var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true); + foreach (var file in files) + { + Logger.InfoFormat("Delete file {0} in {1}", file.ID, parentId); + fileDao.DeleteFile(file.ID); + } + } public void MoveSharedItems(object parentId, object toId, IFolderDao folderDao, IFileDao fileDao) { var fileSecurity = FileSecurity; @@ -1043,7 +1316,41 @@ namespace ASC.Web.Files.Utils } } - public static void ReassignItems(object parentId, Guid fromUserId, Guid toUserId, IFolderDao folderDao, IFileDao fileDao) + public void MoveSharedItems(T parentId, T toId, IFolderDao folderDao, IFileDao fileDao) + { + var fileSecurity = FileSecurity; + + var folders = folderDao.GetFolders(parentId); + foreach (var folder in folders) + { + var shared = folder.Shared + && fileSecurity.GetShares(folder).Any(record => record.Share != FileShare.Restrict); + if (shared) + { + Logger.InfoFormat("Move shared folder {0} from {1} to {2}", folder.ID, parentId, toId); + folderDao.MoveFolder(folder.ID, toId, null); + } + else + { + MoveSharedItems(folder.ID, toId, folderDao, fileDao); + } + } + + var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true); + foreach (var file + in files.Where(file => + file.Shared + && fileSecurity.GetShares(file) + .Any(record => + record.Subject != FileConstant.ShareLinkId + && record.Share != FileShare.Restrict))) + { + Logger.InfoFormat("Move shared file {0} from {1} to {2}", file.ID, parentId, toId); + fileDao.MoveFile(file.ID, toId); + } + } + + public static void ReassignItems(T parentId, Guid fromUserId, Guid toUserId, IFolderDao folderDao, IFileDao fileDao) { var fileIds = fileDao.GetFiles(parentId, new OrderBy(SortedByType.AZ, true), FilterType.ByUser, false, fromUserId, null, true, true) .Where(file => file.CreateBy == fromUserId).Select(file => file.ID); diff --git a/products/ASC.Files/Server/Utils/FileConverter.cs b/products/ASC.Files/Server/Utils/FileConverter.cs index df9ad230b6..7d9160b73f 100644 --- a/products/ASC.Files/Server/Utils/FileConverter.cs +++ b/products/ASC.Files/Server/Utils/FileConverter.cs @@ -318,7 +318,7 @@ namespace ASC.Web.Files.Utils return result != null && result.Progress != 100 && string.IsNullOrEmpty(result.Error); } - public IEnumerable GetStatus(IEnumerable> filesPair) + public IEnumerable GetStatus(IEnumerable, bool>> filesPair) { var fileSecurity = FileSecurity; var result = new List(); diff --git a/products/ASC.Files/Server/Utils/FileShareLink.cs b/products/ASC.Files/Server/Utils/FileShareLink.cs index f3984b6d67..12263b8242 100644 --- a/products/ASC.Files/Server/Utils/FileShareLink.cs +++ b/products/ASC.Files/Server/Utils/FileShareLink.cs @@ -86,6 +86,10 @@ namespace ASC.Web.Files.Utils { return Signature.Read(doc ?? string.Empty, Global.GetDocDbKey()); } + public T Parse(string doc) + { + return Signature.Read(doc ?? string.Empty, Global.GetDocDbKey()); + } public bool Check(string doc, bool checkRead, IFileDao fileDao, out File file) { @@ -93,6 +97,12 @@ namespace ASC.Web.Files.Utils return (!checkRead && (fileShare == FileShare.ReadWrite || fileShare == FileShare.Review || fileShare == FileShare.FillForms || fileShare == FileShare.Comment)) || (checkRead && fileShare != FileShare.Restrict); } + public bool Check(string doc, bool checkRead, IFileDao fileDao, out File file) + { + var fileShare = Check(doc, fileDao, out file); + return (!checkRead && (fileShare == FileShare.ReadWrite || fileShare == FileShare.Review || fileShare == FileShare.FillForms || fileShare == FileShare.Comment)) + || (checkRead && fileShare != FileShare.Restrict); + } public FileShare Check(string doc, IFileDao fileDao, out File file) { @@ -110,6 +120,23 @@ namespace ASC.Web.Files.Utils if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; return FileShare.Restrict; } + + public FileShare Check(string doc, IFileDao fileDao, out File file) + { + file = null; + if (string.IsNullOrEmpty(doc)) return FileShare.Restrict; + var fileId = Parse(doc); + file = fileDao.GetFile(fileId); + if (file == null) return FileShare.Restrict; + + var filesSecurity = FileSecurity; + if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; + if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; + if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; + if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; + if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; + return FileShare.Restrict; + } } public static class FileShareLinkExtension { diff --git a/products/ASC.Files/Server/Utils/FileTracker.cs b/products/ASC.Files/Server/Utils/FileTracker.cs index 8dbaa84efc..092012a892 100644 --- a/products/ASC.Files/Server/Utils/FileTracker.cs +++ b/products/ASC.Files/Server/Utils/FileTracker.cs @@ -164,6 +164,31 @@ namespace ASC.Web.Files.Utils return false; } + public static bool IsEditing(T fileId) + { + var tracker = GetTracker(fileId); + if (tracker != null) + { + var listForRemove = tracker._editingBy + .Where(e => !e.Value.NewScheme && (DateTime.UtcNow - e.Value.TrackTime).Duration() > TrackTimeout) + .ToList(); + foreach (var editTab in listForRemove) + { + tracker._editingBy.Remove(editTab.Key); + } + + if (tracker._editingBy.Count == 0) + { + SetTracker(fileId, null); + return false; + } + + SetTracker(fileId, tracker); + return true; + } + SetTracker(fileId, null); + return false; + } public static bool IsEditingAlone(object fileId) { var tracker = GetTracker(fileId); diff --git a/products/ASC.Files/Server/Utils/FileUploader.cs b/products/ASC.Files/Server/Utils/FileUploader.cs index e15f88f015..8f833f3703 100644 --- a/products/ASC.Files/Server/Utils/FileUploader.cs +++ b/products/ASC.Files/Server/Utils/FileUploader.cs @@ -248,21 +248,15 @@ namespace ASC.Web.Files.Utils return file; } - public ChunkedUploadSession InitiateUpload(string folderId, string fileId, string fileName, long contentLength, bool encrypted) + public ChunkedUploadSession InitiateUpload(T folderId, T fileId, string fileName, long contentLength, bool encrypted) { - if (string.IsNullOrEmpty(folderId)) - folderId = null; - - if (string.IsNullOrEmpty(fileId)) - fileId = null; - - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.ID = fileId; file.FolderID = folderId; file.Title = fileName; file.ContentLength = contentLength; - var dao = DaoFactory.FileDao; + var dao = DaoFactory.GetFileDao(); var uploadSession = dao.CreateUploadSession(file, contentLength); uploadSession.Expired = uploadSession.Created + ChunkedUploadSessionHolder.SlidingExpiration; @@ -278,9 +272,9 @@ namespace ASC.Web.Files.Utils return uploadSession; } - public ChunkedUploadSession UploadChunk(string uploadId, Stream stream, long chunkLength) + public ChunkedUploadSession UploadChunk(string uploadId, Stream stream, long chunkLength) { - var uploadSession = ChunkedUploadSessionHolder.GetSession(uploadId); + var uploadSession = ChunkedUploadSessionHolder.GetSession(uploadId); uploadSession.Expired = DateTime.UtcNow + ChunkedUploadSessionHolder.SlidingExpiration; if (chunkLength <= 0) @@ -301,7 +295,7 @@ namespace ASC.Web.Files.Utils throw FileSizeComment.GetFileSizeException(maxUploadSize); } - var dao = DaoFactory.FileDao; + var dao = DaoFactory.GetFileDao(); dao.UploadChunk(uploadSession, stream, chunkLength); if (uploadSession.BytesUploaded == uploadSession.BytesTotal) @@ -317,14 +311,14 @@ namespace ASC.Web.Files.Utils return uploadSession; } - public void AbortUpload(string uploadId) + public void AbortUpload(string uploadId) { - AbortUpload(ChunkedUploadSessionHolder.GetSession(uploadId)); + AbortUpload(ChunkedUploadSessionHolder.GetSession(uploadId)); } - private void AbortUpload(ChunkedUploadSession uploadSession) + private void AbortUpload(ChunkedUploadSession uploadSession) { - DaoFactory.FileDao.AbortUploadSession(uploadSession); + DaoFactory.GetFileDao().AbortUploadSession(uploadSession); ChunkedUploadSessionHolder.RemoveSession(uploadSession); } From 38eefb5a2009076703f28b38fe9734992e366f7b Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 3 Mar 2020 14:37:40 +0300 Subject: [PATCH 03/30] Files: refactoring --- .../Server/Controllers/FilesController.cs | 67 +- .../Server/Core/Dao/Interfaces/IFolderDao.cs | 4 +- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 30 +- .../Core/Entries/ChunkedUploadSession.cs | 4 +- .../Server/Core/Entries/EncryptionAddress.cs | 4 +- .../ASC.Files/Server/Core/Entries/File.cs | 5 + .../ASC.Files/Server/Core/Entries/Folder.cs | 5 + .../Server/Core/FileStorageService.cs | 242 +-- .../ASC.Files/Server/Core/FilesIntegration.cs | 34 +- .../Server/Core/Security/FileSecurity.cs | 151 +- .../Server/Core/Security/IFileSecurity.cs | 16 +- .../Server/Helpers/DocuSignHelper.cs | 29 +- products/ASC.Files/Server/Helpers/Global.cs | 228 +-- .../Server/HttpHandlers/FileHandler.ashx.cs | 103 +- .../Server/HttpHandlers/SearchHandler.cs | 20 +- .../Server/Model/FileOperationWraper.cs | 22 +- .../ASC.Files/Server/Model/FileWrapper.cs | 7 +- .../Server/Model/FolderContentWrapper.cs | 6 +- .../ASC.Files/Server/Model/FolderWrapper.cs | 6 +- .../Services/DocumentService/Configuration.cs | 1527 ++++++++--------- .../DocumentService/DocumentServiceHelper.cs | 38 +- .../DocumentService/DocumentServiceTracker.cs | 16 +- .../WCFService/FileEntrySerializer.cs | 2 +- .../FileOperations/FileDeleteOperation.cs | 4 +- .../FileOperations/FileDownloadOperation.cs | 2 +- .../FileOperations/FileMoveCopyOperation.cs | 18 +- .../WCFService/IFileStorageService.cs | 2 +- .../WCFService/Wrappers/DataWrapper.cs | 7 +- .../WCFService/Wrappers/MentionWrapper.cs | 3 +- .../ASC.Files/Server/ThirdPartyApp/BoxApp.cs | 18 +- .../Server/ThirdPartyApp/GoogleDriveApp.cs | 7 +- .../Server/ThirdPartyApp/IThirdPartyApp.cs | 8 +- .../ASC.Files/Server/Utils/EntryManager.cs | 395 +---- .../ASC.Files/Server/Utils/FileConverter.cs | 53 +- products/ASC.Files/Server/Utils/FileMarker.cs | 74 +- .../ASC.Files/Server/Utils/FileShareLink.cs | 40 +- .../ASC.Files/Server/Utils/FileSharing.cs | 34 +- .../ASC.Files/Server/Utils/FileUploader.cs | 32 +- 38 files changed, 1422 insertions(+), 1841 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index acab8fc9dc..ebf16cbd60 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -529,12 +529,10 @@ namespace ASC.Api.Documents /// Files /// [Read("file/{fileId}/openedit")] - public Configuration OpenEdit(string fileId, int version, string doc) + public Configuration OpenEdit(string fileId, int version, string doc) { - Configuration configuration; - DocumentServiceHelper.GetParams(fileId, version, doc, true, true, true, out configuration); - configuration.Type = Configuration.EditorType.External; - + DocumentServiceHelper.GetParams(fileId, version, doc, true, true, true, out var configuration); + configuration.Type = EditorType.External; configuration.Token = DocumentServiceHelper.GetSignature(configuration); return configuration; } @@ -667,7 +665,7 @@ namespace ASC.Api.Documents return CreateFile(folderId, title, content, extension); } - private FileWrapper CreateFile(string folderId, string title, string content, string extension) + private FileWrapper CreateFile(T folderId, string title, string content, string extension) { using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) { @@ -767,7 +765,7 @@ namespace ASC.Api.Documents [Create("{folderId}/file")] public FileWrapper CreateFile(string folderId, string title) { - var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); + var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); return FileWrapperHelper.Get(file); } @@ -972,7 +970,7 @@ namespace ASC.Api.Documents var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); - return entries.Select(x => FileWrapperHelper.Get((Files.Core.File)x)); + return entries.Select(x => FileWrapperHelper.Get((File)x)); } /// @@ -994,7 +992,7 @@ namespace ASC.Api.Documents itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); } /// @@ -1016,7 +1014,7 @@ namespace ASC.Api.Documents itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); } /// @@ -1033,7 +1031,7 @@ namespace ASC.Api.Documents itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); } /// @@ -1045,7 +1043,7 @@ namespace ASC.Api.Documents [Update("fileops/terminate")] public IEnumerable TerminateTasks() { - return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); + return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); } @@ -1058,7 +1056,7 @@ namespace ASC.Api.Documents [Read("fileops")] public IEnumerable GetOperationStatuses() { - return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); + return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); } /// @@ -1090,7 +1088,7 @@ namespace ASC.Api.Documents itemList.Add("folder_" + folderId, string.Empty); } - return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); } /// @@ -1111,7 +1109,7 @@ namespace ASC.Api.Documents itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); + return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); } /// @@ -1123,7 +1121,7 @@ namespace ASC.Api.Documents [Update("fileops/emptytrash")] public IEnumerable EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } /// @@ -1165,7 +1163,7 @@ namespace ASC.Api.Documents [Read("file/{fileId}/share")] public IEnumerable GetFileSecurityInfo(string fileId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); return fileShares.Select(FileShareWrapperHelper.Get); } @@ -1179,7 +1177,7 @@ namespace ASC.Api.Documents [Read("folder/{folderId}/share")] public IEnumerable GetFolderSecurityInfo(string folderId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); return fileShares.Select(FileShareWrapperHelper.Get); } @@ -1281,7 +1279,7 @@ namespace ASC.Api.Documents var file = GetFileInfo(fileId); var objectId = "file_" + file.Id; - var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); if (sharedInfo == null || sharedInfo.Share != share) { var list = new ItemList @@ -1299,7 +1297,7 @@ namespace ASC.Api.Documents Aces = list }; FileStorageService.SetAceObject(aceCollection, false); - sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); } return sharedInfo.Link; @@ -1396,7 +1394,7 @@ namespace ASC.Api.Documents ProviderKey = providerKey, }; - var folder = FileStorageService.SaveThirdParty(thirdPartyParams); + var folder = FileStorageService.SaveThirdParty(thirdPartyParams); return FolderWrapperHelper.Get(folder); } @@ -1439,7 +1437,7 @@ namespace ASC.Api.Documents [Delete("thirdparty/{providerId:int}")] public object DeleteThirdParty(int providerId) { - return FileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture)); + return FileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture)); } @@ -1554,7 +1552,7 @@ namespace ASC.Api.Documents } var startIndex = Convert.ToInt32(ApiContext.StartIndex); - return FolderContentWrapperHelper.Get(FileStorageService.GetFolderItems(folderId.ToString(), + return FolderContentWrapperHelper.Get(FileStorageService.GetFolderItems(folderId.ToString(), startIndex, Convert.ToInt32(ApiContext.Count) - 1, //NOTE: in ApiContext +1 filterType, @@ -1567,6 +1565,29 @@ namespace ASC.Api.Documents startIndex); } + private FolderContentWrapper ToFolderContentWrapper(int folderId, Guid userIdOrGroupId, FilterType filterType) + { + if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) + { + sortBy = SortedByType.AZ; + } + + var startIndex = Convert.ToInt32(ApiContext.StartIndex); + var items = FileStorageService.GetFolderItems( + folderId, + startIndex, + Convert.ToInt32(ApiContext.Count) - 1, //NOTE: in ApiContext +1 + filterType, + filterType == FilterType.ByUser, + userIdOrGroupId.ToString(), + ApiContext.FilterValue, + false, + false, + new OrderBy(sortBy, !ApiContext.SortDescending)); + + return FolderContentWrapperHelper.Get(items, startIndex); + } + #region wordpress /// false diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs index 0e9b00cf96..0d05668308 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs @@ -218,9 +218,9 @@ namespace ASC.Files.Core /// /// /// - T GetFolderID(string module, string bunch, Guid data, bool createIfNotExists); + T GetFolderID(string module, string bunch, string data, bool createIfNotExists); - IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists); + IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists); /// /// Returns id folder "Shared Documents" diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index e09f0c8e1f..3aff80867d 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -796,7 +796,7 @@ namespace ASC.Files.Core.Data throw new NotImplementedException(); } - public virtual IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + IEnumerable IFolderDao.GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -868,7 +868,7 @@ namespace ASC.Files.Core.Data throw new NotImplementedException(); } - public virtual int GetFolderID(string module, string bunch, Guid data, bool createIfNotExists) + int IFolderDao.GetFolderID(string module, string bunch, string data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -879,8 +879,13 @@ namespace ASC.Files.Core.Data .Select(r => r.LeftNode) .FirstOrDefault(); - int newFolderId = 0; - if (createIfNotExists && folderId == null) + if (folderId != null) + { + return Convert.ToInt32(folderId); + } + + var newFolderId = 0; + if (createIfNotExists) { var folder = ServiceProvider.GetService>(); folder.ParentFolderID = 0; @@ -889,7 +894,7 @@ namespace ASC.Files.Core.Data case my: folder.FolderType = FolderType.USER; folder.Title = my; - folder.CreateBy = data; + folder.CreateBy = new Guid(data.ToString()); break; case common: folder.FolderType = FolderType.COMMON; @@ -898,7 +903,7 @@ namespace ASC.Files.Core.Data case trash: folder.FolderType = FolderType.TRASH; folder.Title = trash; - folder.CreateBy = data; + folder.CreateBy = new Guid(data.ToString()); break; case share: folder.FolderType = FolderType.SHARE; @@ -937,7 +942,7 @@ namespace ASC.Files.Core.Data int IFolderDao.GetFolderIDProjects(bool createIfNotExists) { - return GetFolderID(FileConstant.ModuleId, projects, Guid.Empty, createIfNotExists); + return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, projects, null, createIfNotExists); } public object GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) @@ -947,7 +952,7 @@ namespace ASC.Files.Core.Data int IFolderDao.GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) { - return GetFolderID(FileConstant.ModuleId, trash, (userId ?? AuthContext.CurrentAccount.ID), createIfNotExists); + return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, trash, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); } public object GetFolderIDCommon(bool createIfNotExists) @@ -957,7 +962,7 @@ namespace ASC.Files.Core.Data int IFolderDao.GetFolderIDCommon(bool createIfNotExists) { - return GetFolderID(FileConstant.ModuleId, common, Guid.Empty, createIfNotExists); + return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, common, null, createIfNotExists); } public object GetFolderIDUser(bool createIfNotExists, Guid? userId = null) @@ -967,7 +972,7 @@ namespace ASC.Files.Core.Data int IFolderDao.GetFolderIDUser(bool createIfNotExists, Guid? userId = null) { - return GetFolderID(FileConstant.ModuleId, my, (userId ?? AuthContext.CurrentAccount.ID), createIfNotExists); + return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, my, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); } public object GetFolderIDShare(bool createIfNotExists) @@ -977,7 +982,7 @@ namespace ASC.Files.Core.Data int IFolderDao.GetFolderIDShare(bool createIfNotExists) { - return GetFolderID(FileConstant.ModuleId, share, Guid.Empty, createIfNotExists); + return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, share, null, createIfNotExists); } #endregion @@ -1181,7 +1186,10 @@ namespace ASC.Files.Core.Data public static DIHelper AddFolderDaoService(this DIHelper services) { services.TryAddScoped(); + services.TryAddScoped, FolderDao>(); services.TryAddTransient(); + services.TryAddTransient>(); + return services .AddFactoryIndexerService() .AddTenantManagerService() diff --git a/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs b/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs index 41771190fc..024546f58f 100644 --- a/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs +++ b/products/ASC.Files/Server/Core/Entries/ChunkedUploadSession.cs @@ -82,11 +82,11 @@ namespace ASC.Files.Core if (f == null) { Logger.ErrorFormat("GetBreadCrumbs {0} with null", session.FolderId); - return string.Empty; + return default; } return f.ID; }) - : new List { session.FolderId }; + : new List { session.FolderId }; return new { diff --git a/products/ASC.Files/Server/Core/Entries/EncryptionAddress.cs b/products/ASC.Files/Server/Core/Entries/EncryptionAddress.cs index bf91e98ad4..94d205d9d9 100644 --- a/products/ASC.Files/Server/Core/Entries/EncryptionAddress.cs +++ b/products/ASC.Files/Server/Core/Entries/EncryptionAddress.cs @@ -58,9 +58,9 @@ namespace ASC.Web.Files.Core.Entries EncryptionLoginProvider = encryptionLoginProvider; } - public IEnumerable GetAddresses(string fileId) + public IEnumerable GetAddresses(T fileId) { - var fileShares = FileSharing.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }).ToList(); + var fileShares = FileSharing.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }).ToList(); fileShares = fileShares.Where(share => !share.SubjectGroup && !share.SubjectId.Equals(FileConstant.ShareLinkId) && share.Share == FileShare.ReadWrite).ToList(); var accountsString = fileShares.Select(share => EncryptionLoginProvider.GetAddress(share.SubjectId)).Where(address => !string.IsNullOrEmpty(address)); return accountsString; diff --git a/products/ASC.Files/Server/Core/Entries/File.cs b/products/ASC.Files/Server/Core/Entries/File.cs index c990739434..0f8f2c2d57 100644 --- a/products/ASC.Files/Server/Core/Entries/File.cs +++ b/products/ASC.Files/Server/Core/Entries/File.cs @@ -75,6 +75,11 @@ namespace ASC.Files.Core set { _folderIdDisplay = value; } } + public new string UniqID + { + get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } + } + public File(Global global, FilesLinkUtility filesLinkUtility, FileUtility fileUtility, FileConverter fileConverter) : base(global, filesLinkUtility, fileUtility, fileConverter) { } diff --git a/products/ASC.Files/Server/Core/Entries/Folder.cs b/products/ASC.Files/Server/Core/Entries/Folder.cs index b43c9a2f94..222b132a0e 100644 --- a/products/ASC.Files/Server/Core/Entries/Folder.cs +++ b/products/ASC.Files/Server/Core/Entries/Folder.cs @@ -71,6 +71,11 @@ namespace ASC.Files.Core set { _folderIdDisplay = value; } } + public new string UniqID + { + get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } + } + public Folder(Global global) : base(global) { } diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index c7cf2c9177..dd7077fcf7 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -197,25 +197,25 @@ namespace ASC.Web.Files.Services.WCFService Logger = optionMonitor.Get("ASC.Files"); } - public Folder GetFolder(string folderId) + public Folder GetFolder(T folderId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder); return folder; } - public ItemList GetFolders(string parentId) + public ItemList> GetFolders(T parentId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); try { var folders = EntryManager.GetEntries(folderDao.GetFolder(parentId), 0, 0, FilterType.FoldersOnly, false, Guid.Empty, string.Empty, false, false, new OrderBy(SortedByType.AZ, true), out var total); - return new ItemList(folders.OfType()); + return new ItemList>(folders.OfType>()); } catch (Exception e) { @@ -223,25 +223,25 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList GetPath(string folderId) + public ItemList GetPath(T folderId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); - return new ItemList(EntryManager.GetBreadCrumbs(folderId, folderDao).Select(f => f.ID)); + return new ItemList(EntryManager.GetBreadCrumbs(folderId, folderDao).Select(f => f.ID)); } - public DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public DataWrapper GetFolderItems(T parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(ssubject) ? Guid.Empty : new Guid(ssubject); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var fileDao = GetFileDao(); - Folder parent = null; + Folder parent = null; try { parent = folderDao.GetFolder(parentId); @@ -257,7 +257,7 @@ namespace ASC.Web.Files.Services.WCFService } ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(parent), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + ErrorIf(!FileSecurity.CanRead(parent), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); ErrorIf(parent.RootFolderType == FolderType.TRASH && !Equals(parent.ID, GlobalFolderHelper.FolderTrash), FilesCommonResource.ErrorMassage_ViewTrashItem); if (orderBy != null) @@ -268,6 +268,7 @@ namespace ASC.Web.Files.Services.WCFService { orderBy = FilesSettingsHelper.DefaultOrder; } + if (Equals(parent.ID, GlobalFolderHelper.FolderShare) && orderBy.SortedBy == SortedByType.DateAndTime) orderBy.SortedBy = SortedByType.New; @@ -294,15 +295,15 @@ namespace ASC.Web.Files.Services.WCFService parent.ParentFolderID = prevVisible.ID; } - parent.Shareable = FileSharing.CanSetAccess(parent) || parent.FolderType == FolderType.SHARE; + parent.Shareable = FileSharing.CanSetAccess(parent) || parent.FolderType == FolderType.SHARE; entries = entries.Where(x => x.FileEntryType == FileEntryType.Folder || !FileConverter.IsConverting((File)x)); - var result = new DataWrapper + var result = new DataWrapper { Total = total, Entries = new ItemList(entries.ToList()), - FolderPathParts = new ItemList(breadCrumbs.Select(f => f.ID)), + FolderPathParts = new ItemList(breadCrumbs.Select(f => f.ID)), FolderInfo = parent, RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew() }; @@ -310,9 +311,9 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetFolderItemsXml(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public object GetFolderItemsXml(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { - var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); + var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(serializer.ToXml(folderItems)) @@ -331,12 +332,12 @@ namespace ASC.Web.Files.Services.WCFService var folderDao = GetFolderDao(); var fileDao = GetFileDao(); - var folders = folderDao.GetFolders(foldersId.ToArray()).Cast(); - folders = FileSecurity.FilterRead(folders); + var folders = folderDao.GetFolders(foldersId.ToArray()); + folders = FileSecurity.FilterRead(folders).ToList(); entries = entries.Concat(folders); - var files = fileDao.GetFiles(filesId.ToArray()).Cast(); - files = FileSecurity.FilterRead(files); + var files = fileDao.GetFiles(filesId.ToArray()); + files = FileSecurity.FilterRead(files).ToList(); entries = entries.Concat(files); entries = EntryManager.FilterEntries(entries, filter, subjectGroup, subjectId, search, true); @@ -347,7 +348,7 @@ namespace ASC.Web.Files.Services.WCFService { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) + && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -356,7 +357,7 @@ namespace ASC.Web.Files.Services.WCFService { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) + && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) { folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -368,18 +369,18 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(entries); } - public Folder CreateNewFolder(string parentId, string title) + public Folder CreateNewFolder(T parentId, string title) { - if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(parentId)) throw new ArgumentException(); + if (string.IsNullOrEmpty(title) || parentId == null) throw new ArgumentException(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var parent = folderDao.GetFolder(parentId); ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanCreate(parent), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(parent), FilesCommonResource.ErrorMassage_SecurityException_Create); try { - var newFolder = ServiceProvider.GetService(); + var newFolder = ServiceProvider.GetService>(); newFolder.Title = title; newFolder.ParentFolderID = parent.ID; @@ -395,14 +396,14 @@ namespace ASC.Web.Files.Services.WCFService } } - public Folder FolderRename(string folderId, string title) + public Folder FolderRename(T folderId, string title) { var tagDao = GetTagDao(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); - if (!FileSecurity.CanDelete(folder) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); + ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); + if (!FileSecurity.CanDelete(folder) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); var folderAccess = folder.Access; @@ -429,8 +430,10 @@ namespace ASC.Web.Files.Services.WCFService if (folder.RootFolderType == FolderType.USER && !Equals(folder.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(folder.ParentFolderID))) - folder.FolderIdDisplay = GlobalFolderHelper.FolderShare; + && !FileSecurity.CanRead(folderDao.GetFolder(folder.ParentFolderID))) + { + folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } return folder; } @@ -444,16 +447,18 @@ namespace ASC.Web.Files.Services.WCFService ? fileDao.GetFile(fileId, version) : fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); EntryManager.SetFileStatus(file); if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } } return file; @@ -468,7 +473,7 @@ namespace ASC.Web.Files.Services.WCFService var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); var parent = folderDao.GetFolder(parentId == null || parentId.Equals(default) ? file.FolderID : parentId); ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); @@ -487,14 +492,14 @@ namespace ASC.Web.Files.Services.WCFService { orderBy = FilesSettingsHelper.DefaultOrder; } - if (Equals(parent.ID, GlobalFolderHelper.FolderShare) && orderBy.SortedBy == SortedByType.DateAndTime) + if (Equals(parent.ID, GlobalFolderHelper.GetFolderShare()) && orderBy.SortedBy == SortedByType.DateAndTime) { orderBy.SortedBy = SortedByType.New; } var entries = Enumerable.Empty(); - if (!FileSecurity.CanRead(parent)) + if (!FileSecurity.CanRead(parent)) { file.FolderID = GlobalFolderHelper.GetFolderShare(); entries = entries.Concat(new[] { file }); @@ -518,7 +523,7 @@ namespace ASC.Web.Files.Services.WCFService var previewedType = new[] { FileType.Image, FileType.Audio, FileType.Video }; var result = - FileSecurity.FilterRead(entries) + FileSecurity.FilterRead(entries.OfType>()) .OfType>() .Where(f => previewedType.Contains(FileUtility.GetFileTypeByFileName(f.Title))); @@ -535,7 +540,7 @@ namespace ASC.Web.Files.Services.WCFService var folder = folderDao.GetFolder(fileWrapper.ParentId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_CreateNewFolderInTrash); - ErrorIf(!FileSecurity.CanCreate(folder), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(folder), FilesCommonResource.ErrorMassage_SecurityException_Create); var file = ServiceProvider.GetService>(); file.FolderID = folder.ID; @@ -575,7 +580,7 @@ namespace ASC.Web.Files.Services.WCFService } FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileCreated, file.Title); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); return file; } @@ -622,7 +627,7 @@ namespace ASC.Web.Files.Services.WCFService foreach (var file in fileDao.GetFiles(ids)) { - if (file == null || !FileSecurity.CanEdit(file) && !FileSecurity.CanReview(file)) continue; + if (file == null || !FileSecurity.CanEdit(file) && !FileSecurity.CanReview(file)) continue; var usersId = FileTracker.GetEditingBy(file.ID); var value = string.Join(", ", usersId.Select(userId => Global.GetUserName(userId, true)).ToArray()); @@ -632,7 +637,7 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public File SaveEditing(string fileId, string fileExtension, string fileuri, Stream stream, string doc = null, bool forcesave = false) + public File SaveEditing(T fileId, string fileExtension, string fileuri, Stream stream, string doc = null, bool forcesave = false) { try { @@ -655,7 +660,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public File UpdateFileStream(string fileId, Stream stream, bool encrypted) + public File UpdateFileStream(T fileId, Stream stream, bool encrypted) { try { @@ -678,7 +683,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public string StartEdit(string fileId, bool editingAlone = false, string doc = null) + public string StartEdit(T fileId, bool editingAlone = false, string doc = null) { try { @@ -687,7 +692,7 @@ namespace ASC.Web.Files.Services.WCFService { ErrorIf(FileTracker.IsEditing(fileId), FilesCommonResource.ErrorMassage_SecurityException_EditFileTwice); - app = ThirdPartySelector.GetAppByFileId(fileId); + app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { EntryManager.TrackEditing(fileId, Guid.Empty, AuthContext.CurrentAccount.ID, doc, true); @@ -697,17 +702,17 @@ namespace ASC.Web.Files.Services.WCFService return DocumentServiceHelper.GetDocKey(fileId, -1, DateTime.MinValue); } - DocumentService.Configuration configuration; + Configuration configuration; - app = ThirdPartySelector.GetAppByFileId(fileId); + app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { - DocumentServiceHelper.GetParams(fileId, -1, doc, true, true, false, out configuration); + DocumentServiceHelper.GetParams(fileId.ToString(), -1, doc, true, true, false, out configuration); } else { - var file = app.GetFile(fileId, out var editable); - DocumentServiceHelper.GetParams(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false, out configuration); + var file = app.GetFile(fileId.ToString(), out var editable); + DocumentServiceHelper.GetParams(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false, out configuration); } ErrorIf(!configuration.EditorConfig.ModeWrite @@ -718,7 +723,7 @@ namespace ASC.Web.Files.Services.WCFService !string.IsNullOrEmpty(configuration.ErrorMessage) ? configuration.ErrorMessage : FilesCommonResource.ErrorMassage_SecurityException_EditFile); var key = configuration.Document.Key; - if (!DocumentServiceTrackerHelper.StartTrack(fileId, key)) + if (!DocumentServiceTrackerHelper.StartTrack(fileId.ToString(), key)) { throw new Exception(FilesCommonResource.ErrorMassage_StartEditing); } @@ -732,7 +737,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public File FileRename(string fileId, string title) + public File FileRename(T fileId, string title) { try { @@ -750,9 +755,11 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) - file.FolderIdDisplay = GlobalFolderHelper.FolderShare; + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + { + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + } } return file; @@ -767,7 +774,7 @@ namespace ASC.Web.Files.Services.WCFService { var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); return new ItemList>(fileDao.GetFileHistory(fileId)); } @@ -781,7 +788,7 @@ namespace ASC.Web.Files.Services.WCFService && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -795,7 +802,7 @@ namespace ASC.Web.Files.Services.WCFService var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId, version); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanEdit(file) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); + ErrorIf(!FileSecurity.CanEdit(file) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile); ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -818,7 +825,7 @@ namespace ASC.Web.Files.Services.WCFService && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -834,7 +841,7 @@ namespace ASC.Web.Files.Services.WCFService var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanEdit(file) || lockfile && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); + ErrorIf(!FileSecurity.CanEdit(file) || lockfile && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); var tagLocked = tagDao.GetTags(file.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); @@ -885,7 +892,7 @@ namespace ASC.Web.Files.Services.WCFService && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -902,7 +909,7 @@ namespace ASC.Web.Files.Services.WCFService file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest); return new ItemList(fileDao.GetEditHistory(DocumentServiceHelper, file.ID)); @@ -927,7 +934,7 @@ namespace ASC.Web.Files.Services.WCFService } ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest); var result = new EditHistoryData @@ -1021,12 +1028,12 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetNewItems(string folderId) + public object GetNewItems(T folderId) { try { - Folder folder; - var folderDao = GetFolderDao(); + Folder folder; + var folderDao = GetFolderDao(); folder = folderDao.GetFolder(folderId); var result = FileMarker.MarkedItems(folder); @@ -1080,33 +1087,33 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(resultList.ToList()); } - public ItemList GetThirdPartyFolder(int folderType = 0) + public ItemList> GetThirdPartyFolder(int folderType = 0) { var providerDao = GetProviderDao(); - if (providerDao == null) return new ItemList(); + if (providerDao == null) return new ItemList>(); var providersInfo = providerDao.GetProvidersInfo((FolderType)folderType); var folders = providersInfo.Select(providerInfo => { - var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo); + var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo); folder.NewForMe = folder.RootFolderType == FolderType.COMMON ? 1 : 0; return folder; }); - return new ItemList(folders); + return new ItemList>(folders); } - public Folder SaveThirdParty(ThirdPartyParams thirdPartyParams) + public Folder SaveThirdParty(ThirdPartyParams thirdPartyParams) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var providerDao = GetProviderDao(); if (providerDao == null) return null; ErrorIf(thirdPartyParams == null, FilesCommonResource.ErrorMassage_BadRequest); var parentFolder = folderDao.GetFolder(thirdPartyParams.Corporate && !CoreBaseSettings.Personal ? GlobalFolderHelper.FolderCommon : GlobalFolderHelper.FolderMy); - ErrorIf(!FileSecurity.CanCreate(parentFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(parentFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); ErrorIf(!Global.IsAdministrator && !FilesSettingsHelper.EnableThirdParty, FilesCommonResource.ErrorMassage_SecurityException_Create); var lostFolderType = FolderType.USER; @@ -1151,7 +1158,7 @@ namespace ASC.Web.Files.Services.WCFService lostFolderType = lostProvider.RootFolderType; if (lostProvider.RootFolderType == FolderType.COMMON && !thirdPartyParams.Corporate) { - var lostFolder = folderDao.GetFolder(lostProvider.RootFolderId); + var lostFolder = folderDao.GetFolder((int)lostProvider.RootFolderId); FileMarker.RemoveMarkAsNewForAll(lostFolder); } @@ -1162,20 +1169,21 @@ namespace ASC.Web.Files.Services.WCFService var provider = providerDao.GetProviderInfo(curProviderId); provider.InvalidateStorage(); - var folder = folderDao.GetFolder(provider.RootFolderId); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + var folderDao1 = GetFolderDao(); + var folder = folderDao1.GetFolder((T)Convert.ChangeType(provider.RootFolderId, typeof(T))); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); FilesMessageService.Send(parentFolder, GetHttpHeaders(), messageAction, folder.ID.ToString(), provider.ProviderKey); if (thirdPartyParams.Corporate && lostFolderType != FolderType.COMMON) { - FileMarker.MarkAsNew(folder); + FileMarker.MarkAsNew(folder); } return folder; } - public object DeleteThirdParty(string providerId) + public object DeleteThirdParty(string providerId) { var providerDao = GetProviderDao(); if (providerDao == null) return null; @@ -1183,8 +1191,8 @@ namespace ASC.Web.Files.Services.WCFService var curProviderId = Convert.ToInt32(providerId); var providerInfo = providerDao.GetProviderInfo(curProviderId); - var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo); - ErrorIf(!FileSecurity.CanDelete(folder), FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder); + var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo); + ErrorIf(!FileSecurity.CanDelete(folder), FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder); if (providerInfo.RootFolderType == FolderType.COMMON) { @@ -1226,7 +1234,7 @@ namespace ASC.Web.Files.Services.WCFService return null; } - public string SendDocuSign(string fileId, DocuSignData docuSignData) + public string SendDocuSign(T fileId, DocuSignData docuSignData) { try { @@ -1280,7 +1288,7 @@ namespace ASC.Web.Files.Services.WCFService var toFolder = folderDao.GetFolder(destFolderId); ErrorIf(toFolder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); foreach (var id in filesId) { @@ -1333,7 +1341,7 @@ namespace ASC.Web.Files.Services.WCFService { ParseArrayItems(items, out var foldersId, out var filesId); - result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); + result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); } else { @@ -1384,7 +1392,7 @@ namespace ASC.Web.Files.Services.WCFService continue; } - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); var startConvert = Convert.ToBoolean(fileInfo[2]); if (startConvert && FileConverter.MustConvert(file)) @@ -1513,35 +1521,35 @@ namespace ASC.Web.Files.Services.WCFService //delete My userFrom folder folderDao.DeleteFolder(folderIdFromMy); - GlobalFolderHelper.FolderMy = userId; + GlobalFolderHelper.SetFolderMy(userId); } //delete all from Trash var folderIdFromTrash = folderDao.GetFolderIDTrash(false, userId); if (!Equals(folderIdFromTrash, 0)) { - EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao); + EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao); folderDao.DeleteFolder(folderIdFromTrash); GlobalFolderHelper.FolderTrash = userId; } - EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userId, AuthContext.CurrentAccount.ID, folderDao, fileDao); + EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userId, AuthContext.CurrentAccount.ID, folderDao, fileDao); } - public ItemList GetSharedInfo(ItemList objectIds) + public ItemList GetSharedInfo(ItemList objectIds) { - return FileSharing.GetSharedInfo(objectIds); + return FileSharing.GetSharedInfo(objectIds); } - public ItemList GetSharedInfoShort(string objectId) + public ItemList GetSharedInfoShort(string objectId) { - return FileSharing.GetSharedInfoShort(objectId); + return FileSharing.GetSharedInfoShort(objectId); } public ItemList SetAceObject(AceCollection aceCollection, bool notify) { var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var result = new ItemList(); foreach (var objectId in aceCollection.Entries) { @@ -1554,7 +1562,7 @@ namespace ASC.Web.Files.Services.WCFService try { - var changed = FileSharingAceHelper.SetAceObject(aceCollection.Aces, entry, notify, aceCollection.Message); + var changed = FileSharingAceHelper.SetAceObject(aceCollection.Aces, entry, notify, aceCollection.Message); if (changed) { FilesMessageService.Send(entry, GetHttpHeaders(), @@ -1588,7 +1596,7 @@ namespace ASC.Web.Files.Services.WCFService entries.AddRange(filesId.Select(fileId => fileDao.GetFile(fileId))); entries.AddRange(foldersId.Select(folderDao.GetFolder)); - FileSharingAceHelper.RemoveAce(entries); + FileSharingAceHelper.RemoveAce(entries); } public string GetShortenLink(T fileId) @@ -1596,7 +1604,7 @@ namespace ASC.Web.Files.Services.WCFService File file; var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); - ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); var shareLink = FileShareLink.GetLink(file); try @@ -1627,7 +1635,7 @@ namespace ASC.Web.Files.Services.WCFService try { - var changed = FileSharingAceHelper.SetAceObject(aces, file, false, null); + var changed = FileSharingAceHelper.SetAceObject(aces, file, false, null); if (changed) { FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdatedAccess, file.Title); @@ -1654,9 +1662,9 @@ namespace ASC.Web.Files.Services.WCFService ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); var usersIdWithAccess = new List(); - if (FileSharing.CanSetAccess(file)) + if (FileSharing.CanSetAccess(file)) { - var access = FileSharing.GetSharedInfo(file); + var access = FileSharing.GetSharedInfo(file); usersIdWithAccess = access.Where(aceWrapper => !aceWrapper.SubjectGroup && aceWrapper.Share != FileShare.Restrict) .Select(aceWrapper => aceWrapper.SubjectId) .ToList(); @@ -1691,7 +1699,7 @@ namespace ASC.Web.Files.Services.WCFService ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - ErrorIf(!fileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!fileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(mentionMessage == null || mentionMessage.Emails == null, FilesCommonResource.ErrorMassage_BadRequest); var changed = false; @@ -1703,7 +1711,7 @@ namespace ASC.Web.Files.Services.WCFService { if (!canShare.HasValue) { - canShare = FileSharing.CanSetAccess(file); + canShare = FileSharing.CanSetAccess(file); } var recipient = UserManager.GetUserByEmail(email); @@ -1713,7 +1721,7 @@ namespace ASC.Web.Files.Services.WCFService continue; } - if (!fileSecurity.CanRead(file, recipient.ID)) + if (!fileSecurity.CanRead(file, recipient.ID)) { if (!canShare.Value) { @@ -1732,7 +1740,7 @@ namespace ASC.Web.Files.Services.WCFService } }; - changed |= FileSharingAceHelper.SetAceObject(aces, file, false, null); + changed |= FileSharingAceHelper.SetAceObject(aces, file, false, null); recipients.Add(recipient.ID); } @@ -1755,8 +1763,7 @@ namespace ASC.Web.Files.Services.WCFService var fileLink = FilesLinkUtility.GetFileWebEditorUrl(file.ID); if (mentionMessage.ActionLink != null) { - fileLink += "&" + FilesLinkUtility.Anchor + "=" + HttpUtility.UrlEncode( - DocumentService.Configuration.EditorConfiguration.ActionLinkConfig.Serialize(mentionMessage.ActionLink)); + fileLink += "&" + FilesLinkUtility.Anchor + "=" + HttpUtility.UrlEncode(ActionLinkConfig.Serialize(mentionMessage.ActionLink)); } var message = (mentionMessage.Message ?? "").Trim(); @@ -1768,7 +1775,7 @@ namespace ASC.Web.Files.Services.WCFService NotifyClient.SendEditorMentions(file, fileLink, recipients, message); - return changed ? GetSharedInfoShort("file_" + fileId) : null; + return changed ? GetSharedInfoShort("file_" + fileId) : null; } public ItemList GetMailAccounts() @@ -1809,12 +1816,12 @@ namespace ASC.Web.Files.Services.WCFService var entries = new List(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folders = folderDao.GetFolders(foldersId.ToArray()); foreach (var folder in folders) { - ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException); ErrorIf(folder.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException); if (folder.ProviderEntry) continue; @@ -1824,7 +1831,7 @@ namespace ASC.Web.Files.Services.WCFService var folderAccess = folder.Access; newFolder.CreateBy = userInfo.ID; - var newFolderID = folderDao.SaveFolder((Folder)newFolder); + var newFolderID = folderDao.SaveFolder((Folder)newFolder); newFolder = folderDao.GetFolder(newFolderID); newFolder.Access = folderAccess; @@ -1839,7 +1846,7 @@ namespace ASC.Web.Files.Services.WCFService foreach (var file in files) { - ErrorIf(!FileSecurity.CanEdit(file), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSecurity.CanEdit(file), FilesCommonResource.ErrorMassage_SecurityException); ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile); ErrorIf(FileTracker.IsEditing(file.ID), FilesCommonResource.ErrorMassage_UpdateEditingFile); ErrorIf(file.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException); @@ -1867,7 +1874,7 @@ namespace ASC.Web.Files.Services.WCFService newFile = fileDao.SaveFile(newFile, stream); } - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); EntryManager.SetFileStatus(newFile); @@ -1939,11 +1946,6 @@ namespace ASC.Web.Files.Services.WCFService return ""; //TODO: Studio.UserControls.Common.HelpCenter.HelpCenter.RenderControlToString(); } - private IFolderDao GetFolderDao() - { - return DaoFactory.FolderDao; - } - private IFolderDao GetFolderDao() { return DaoFactory.GetFolderDao(); diff --git a/products/ASC.Files/Server/Core/FilesIntegration.cs b/products/ASC.Files/Server/Core/FilesIntegration.cs index 8be9cca643..278f6c0338 100644 --- a/products/ASC.Files/Server/Core/FilesIntegration.cs +++ b/products/ASC.Files/Server/Core/FilesIntegration.cs @@ -29,7 +29,6 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; -using ASC.Data.Storage; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Security; @@ -52,22 +51,24 @@ namespace ASC.Web.Files.Api GlobalStore = globalStore; } - public object RegisterBunch(string module, string bunch, string data) + public T RegisterBunch(string module, string bunch, string data) { - var folderDao = GetFolderDao(); + var folderDao = DaoFactory.GetFolderDao(); return folderDao.GetFolderID(module, bunch, data, true); } - public IEnumerable RegisterBunchFolders(string module, string bunch, IEnumerable data) + public IEnumerable RegisterBunchFolders(string module, string bunch, IEnumerable data) { if (data == null) throw new ArgumentNullException("data"); data = data.ToList(); if (!data.Any()) - return new List(); + { + return new List(); + } - var folderDao = GetFolderDao(); + var folderDao = DaoFactory.GetFolderDao(); return folderDao.GetFolderIDs(module, bunch, data, true); } @@ -88,27 +89,6 @@ namespace ASC.Web.Files.Api } } - public IFileDao GetFileDao() - { - return DaoFactory.FileDao; - } - - public IFolderDao GetFolderDao() - { - return DaoFactory.FolderDao; - } - - public ITagDao TagDao() - { - return DaoFactory.TagDao; - } - - public IDataStore GetStore() - { - return GlobalStore.GetStore(); - } - - internal static IFileSecurity GetFileSecurity(string path) { if (string.IsNullOrEmpty(path)) return null; diff --git a/products/ASC.Files/Server/Core/Security/FileSecurity.cs b/products/ASC.Files/Server/Core/Security/FileSecurity.cs index 2f7aa81ea9..58db3d8e3b 100644 --- a/products/ASC.Files/Server/Core/Security/FileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/FileSecurity.cs @@ -101,87 +101,87 @@ namespace ASC.Files.Core.Security FileSecurityCommon = fileSecurityCommon; } - public List> CanRead(IEnumerable entry, Guid userId) + public List> CanRead(IEnumerable entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Read); + return Can(entry, userId, FilesSecurityActions.Read); } - public bool CanRead(FileEntry entry, Guid userId) + public bool CanRead(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Read); + return Can(entry, userId, FilesSecurityActions.Read); } - public bool CanComment(FileEntry entry, Guid userId) + public bool CanComment(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Comment); + return Can(entry, userId, FilesSecurityActions.Comment); } - public bool CanFillForms(FileEntry entry, Guid userId) + public bool CanFillForms(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.FillForms); + return Can(entry, userId, FilesSecurityActions.FillForms); } - public bool CanReview(FileEntry entry, Guid userId) + public bool CanReview(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Review); + return Can(entry, userId, FilesSecurityActions.Review); } - public bool CanCreate(FileEntry entry, Guid userId) + public bool CanCreate(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Create); + return Can(entry, userId, FilesSecurityActions.Create); } - public bool CanEdit(FileEntry entry, Guid userId) + public bool CanEdit(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Edit); + return Can(entry, userId, FilesSecurityActions.Edit); } - public bool CanDelete(FileEntry entry, Guid userId) + public bool CanDelete(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Delete); + return Can(entry, userId, FilesSecurityActions.Delete); } - public bool CanRead(FileEntry entry) + public bool CanRead(FileEntry entry) { - return CanRead(entry, AuthContext.CurrentAccount.ID); + return CanRead(entry, AuthContext.CurrentAccount.ID); } - public bool CanComment(FileEntry entry) + public bool CanComment(FileEntry entry) { - return CanComment(entry, AuthContext.CurrentAccount.ID); + return CanComment(entry, AuthContext.CurrentAccount.ID); } - public bool CanFillForms(FileEntry entry) + public bool CanFillForms(FileEntry entry) { - return CanFillForms(entry, AuthContext.CurrentAccount.ID); + return CanFillForms(entry, AuthContext.CurrentAccount.ID); } - public bool CanReview(FileEntry entry) + public bool CanReview(FileEntry entry) { - return CanReview(entry, AuthContext.CurrentAccount.ID); + return CanReview(entry, AuthContext.CurrentAccount.ID); } - public bool CanCreate(FileEntry entry) + public bool CanCreate(FileEntry entry) { - return CanCreate(entry, AuthContext.CurrentAccount.ID); + return CanCreate(entry, AuthContext.CurrentAccount.ID); } - public bool CanEdit(FileEntry entry) + public bool CanEdit(FileEntry entry) { - return CanEdit(entry, AuthContext.CurrentAccount.ID); + return CanEdit(entry, AuthContext.CurrentAccount.ID); } - public bool CanDelete(FileEntry entry) + public bool CanDelete(FileEntry entry) { - return CanDelete(entry, AuthContext.CurrentAccount.ID); + return CanDelete(entry, AuthContext.CurrentAccount.ID); } - public IEnumerable WhoCanRead(FileEntry entry) + public IEnumerable WhoCanRead(FileEntry entry) { - return WhoCan(entry, FilesSecurityActions.Read); + return WhoCan(entry, FilesSecurityActions.Read); } - private IEnumerable WhoCan(FileEntry entry, FilesSecurityActions action) + private IEnumerable WhoCan(FileEntry entry, FilesSecurityActions action) { var shares = GetShares(entry); @@ -246,7 +246,7 @@ namespace ASC.Files.Core.Security if (adapter != null) { - return adapter.WhoCanRead(entry); + return adapter.WhoCanRead(entry); } } } @@ -276,57 +276,42 @@ namespace ASC.Files.Core.Security return new[] { x.Subject }; }) .Distinct() - .Where(x => Can(entry, x, action)) + .Where(x => Can(entry, x, action)) .ToList(); } - public IEnumerable FilterRead(IEnumerable entries) - { - return Filter(entries, FilesSecurityActions.Read, AuthContext.CurrentAccount.ID); - } - - public IEnumerable FilterRead(IEnumerable entries) - { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast(); - } - public IEnumerable> FilterRead(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); - } - - public IEnumerable FilterRead(IEnumerable entries) - { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast(); + return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); } public IEnumerable> FilterRead(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); + return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); } - public IEnumerable FilterEdit(IEnumerable entries) + public IEnumerable> FilterEdit(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast(); + return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); } - public IEnumerable FilterEdit(IEnumerable entries) + public IEnumerable> FilterEdit(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast(); + return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); } - private bool Can(FileEntry entry, Guid userId, FilesSecurityActions action) + private bool Can(FileEntry entry, Guid userId, FilesSecurityActions action) { - return Filter(new[] { entry }, action, userId).Any(); + return Filter(new[] { entry }, action, userId).Any(); } - private List> Can(IEnumerable entry, Guid userId, FilesSecurityActions action) + private List> Can(IEnumerable entry, Guid userId, FilesSecurityActions action) { - var filtres = Filter(entry, action, userId); + var filtres = Filter(entry, action, userId); return entry.Select(r => new Tuple(r, filtres.Any(a => a.ID.Equals(r.ID)))).ToList(); } - private IEnumerable Filter(IEnumerable entries, FilesSecurityActions action, Guid userId) + private IEnumerable Filter(IEnumerable entries, FilesSecurityActions action, Guid userId) { if (entries == null || !entries.Any()) return Enumerable.Empty(); @@ -481,51 +466,51 @@ namespace ASC.Files.Core.Security if (adapter == null) continue; - if (adapter.CanRead(e, userId) && - adapter.CanCreate(e, userId) && - adapter.CanEdit(e, userId) && - adapter.CanDelete(e, userId)) + if (adapter.CanRead(e, userId) && + adapter.CanCreate(e, userId) && + adapter.CanEdit(e, userId) && + adapter.CanDelete(e, userId)) { e.Access = FileShare.None; result.Add(e); } - else if (action == FilesSecurityActions.Comment && adapter.CanComment(e, userId)) + else if (action == FilesSecurityActions.Comment && adapter.CanComment(e, userId)) { e.Access = FileShare.Comment; result.Add(e); } - else if (action == FilesSecurityActions.FillForms && adapter.CanFillForms(e, userId)) + else if (action == FilesSecurityActions.FillForms && adapter.CanFillForms(e, userId)) { e.Access = FileShare.FillForms; result.Add(e); } - else if (action == FilesSecurityActions.Review && adapter.CanReview(e, userId)) + else if (action == FilesSecurityActions.Review && adapter.CanReview(e, userId)) { e.Access = FileShare.Review; result.Add(e); } - else if (action == FilesSecurityActions.Create && adapter.CanCreate(e, userId)) + else if (action == FilesSecurityActions.Create && adapter.CanCreate(e, userId)) { e.Access = FileShare.ReadWrite; result.Add(e); } - else if (action == FilesSecurityActions.Delete && adapter.CanDelete(e, userId)) + else if (action == FilesSecurityActions.Delete && adapter.CanDelete(e, userId)) { e.Access = FileShare.ReadWrite; result.Add(e); } - else if (action == FilesSecurityActions.Read && adapter.CanRead(e, userId)) + else if (action == FilesSecurityActions.Read && adapter.CanRead(e, userId)) { - if (adapter.CanCreate(e, userId) || - adapter.CanDelete(e, userId) || - adapter.CanEdit(e, userId)) + if (adapter.CanCreate(e, userId) || + adapter.CanDelete(e, userId) || + adapter.CanEdit(e, userId)) e.Access = FileShare.ReadWrite; else e.Access = FileShare.Read; result.Add(e); } - else if (action == FilesSecurityActions.Edit && adapter.CanEdit(e, userId)) + else if (action == FilesSecurityActions.Edit && adapter.CanEdit(e, userId)) { e.Access = FileShare.ReadWrite; @@ -583,10 +568,10 @@ namespace ASC.Files.Core.Security return daoFactory.SecurityDao.GetShares(entry); } - public List GetSharesForMe(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false) + public List GetSharesForMe(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false) { - var folderDao = daoFactory.FolderDao; - var fileDao = daoFactory.FileDao; + var folderDao = daoFactory.GetFolderDao(); + var fileDao = daoFactory.GetFileDao(); var securityDao = daoFactory.SecurityDao; var subjects = GetUserSubjects(AuthContext.CurrentAccount.ID); @@ -620,14 +605,14 @@ namespace ASC.Files.Core.Security if (filterType != FilterType.FoldersOnly) { - var files = fileDao.GetFilesForShare(fileIds.Keys.ToArray(), filterType, subjectGroup, subjectID, searchText, searchInContent); + var files = fileDao.GetFilesForShare(fileIds.Keys.Select(r => (T)r).ToArray(), filterType, subjectGroup, subjectID, searchText, searchInContent); files.ForEach(x => { if (fileIds.ContainsKey(x.ID)) { x.Access = fileIds[x.ID]; - x.FolderIdDisplay = GlobalFolder.GetFolderShare(folderDao); + x.FolderIdDisplay = GlobalFolder.GetFolderShare(daoFactory); } }); @@ -636,7 +621,7 @@ namespace ASC.Files.Core.Security if (filterType == FilterType.None || filterType == FilterType.FoldersOnly) { - var folders = folderDao.GetFolders(folderIds.Keys.ToArray(), filterType, subjectGroup, subjectID, searchText, withSubfolders, false); + var folders = folderDao.GetFolders(folderIds.Keys.Select(r => (T)r).ToArray(), filterType, subjectGroup, subjectID, searchText, withSubfolders, false); if (withSubfolders) { @@ -647,7 +632,7 @@ namespace ASC.Files.Core.Security if (folderIds.ContainsKey(x.ID)) { x.Access = folderIds[x.ID]; - x.FolderIdDisplay = GlobalFolder.GetFolderShare(folderDao); + x.FolderIdDisplay = GlobalFolder.GetFolderShare(daoFactory); } }); @@ -656,7 +641,7 @@ namespace ASC.Files.Core.Security if (filterType != FilterType.FoldersOnly && withSubfolders) { - var filesInSharedFolders = fileDao.GetFiles(folderIds.Keys.ToArray(), filterType, subjectGroup, subjectID, searchText, searchInContent); + var filesInSharedFolders = fileDao.GetFiles(folderIds.Keys.Select(r => (T)r).ToArray(), filterType, subjectGroup, subjectID, searchText, searchInContent); filesInSharedFolders = FilterRead(filesInSharedFolders).ToList(); entries.AddRange(filesInSharedFolders); entries = entries.Distinct().ToList(); diff --git a/products/ASC.Files/Server/Core/Security/IFileSecurity.cs b/products/ASC.Files/Server/Core/Security/IFileSecurity.cs index 9b35da0afd..594f0dddc1 100644 --- a/products/ASC.Files/Server/Core/Security/IFileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/IFileSecurity.cs @@ -31,20 +31,20 @@ namespace ASC.Files.Core.Security { public interface IFileSecurity { - bool CanRead(FileEntry entry, Guid userId); + bool CanRead(FileEntry entry, Guid userId); - bool CanComment(FileEntry entry, Guid userId); + bool CanComment(FileEntry entry, Guid userId); - bool CanReview(FileEntry entry, Guid userId); + bool CanReview(FileEntry entry, Guid userId); - bool CanFillForms(FileEntry entry, Guid userId); + bool CanFillForms(FileEntry entry, Guid userId); - bool CanCreate(FileEntry entry, Guid userId); + bool CanCreate(FileEntry entry, Guid userId); - bool CanEdit(FileEntry entry, Guid userId); + bool CanEdit(FileEntry entry, Guid userId); - bool CanDelete(FileEntry entry, Guid userId); + bool CanDelete(FileEntry entry, Guid userId); - IEnumerable WhoCanRead(FileEntry entry); + IEnumerable WhoCanRead(FileEntry entry); } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs index 17dbceb48d..57e6d2d30d 100644 --- a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs +++ b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs @@ -62,9 +62,6 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; -using File = ASC.Files.Core.File; -using Folder = ASC.Files.Core.Folder; - namespace ASC.Web.Files.Helpers { public class DocuSignToken @@ -206,7 +203,7 @@ namespace ASC.Web.Files.Helpers return true; } - public string SendDocuSign(object fileId, DocuSignData docuSignData, Dictionary requestHeaders) + public string SendDocuSign(T fileId, DocuSignData docuSignData, Dictionary requestHeaders) { if (docuSignData == null) throw new ArgumentNullException("docuSignData"); var token = DocuSignToken.GetToken(); @@ -252,12 +249,12 @@ namespace ASC.Web.Files.Helpers return configuration; } - private Document CreateDocument(object fileId, string documentName, string folderId, out File file) + private Document CreateDocument(T fileId, string documentName, string folderId, out File file) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); file = fileDao.GetFile(fileId); if (file == null) throw new Exception(FilesCommonResource.ErrorMassage_FileNotFound); - if (!FileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + if (!FileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); if (!SupportedFormats.Contains(FileUtility.GetFileExtension(file.Title))) throw new ArgumentException(FilesCommonResource.ErrorMassage_NotSupportedFormat); if (file.ContentLength > MaxFileSize) throw new Exception(FileSizeComment.GetFileSizeExceptionString(MaxFileSize)); @@ -376,7 +373,7 @@ namespace ASC.Web.Files.Helpers return url.Url; } - public File SaveDocument(string envelopeId, string documentId, string documentName, object folderId) + public File SaveDocument(string envelopeId, string documentId, string documentName, T folderId) { if (string.IsNullOrEmpty(envelopeId)) throw new ArgumentNullException("envelopeId"); if (string.IsNullOrEmpty(documentId)) throw new ArgumentNullException("documentId"); @@ -385,22 +382,22 @@ namespace ASC.Web.Files.Helpers var account = GetDocuSignAccount(token); var configuration = GetConfiguration(account, token); - var fileDao = DaoFactory.FileDao; - var folderDao = DaoFactory.FolderDao; + var fileDao = DaoFactory.GetFileDao(); + var folderDao = DaoFactory.GetFolderDao(); if (string.IsNullOrEmpty(documentName)) { documentName = "new.pdf"; } - Folder folder; + Folder folder; if (folderId == null || (folder = folderDao.GetFolder(folderId)) == null || folder.RootFolderType == FolderType.TRASH - || !FileSecurity.CanCreate(folder)) + || !FileSecurity.CanCreate(folder)) { - if (GlobalFolderHelper.FolderMy != null) + if (GlobalFolderHelper.FolderMy != 0) { - folderId = GlobalFolderHelper.FolderMy; + folderId = GlobalFolderHelper.GetFolderMy(); } else { @@ -408,7 +405,7 @@ namespace ASC.Web.Files.Helpers } } - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.FolderID = folderId; file.Comment = FilesCommonResource.CommentCreateByDocuSign; file.Title = FileUtility.ReplaceFileExtension(documentName, ".pdf"); @@ -423,7 +420,7 @@ namespace ASC.Web.Files.Helpers FilesMessageService.Send(file, MessageInitiator.ThirdPartyProvider, MessageAction.DocumentSignComplete, "DocuSign", file.Title); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); return file; } diff --git a/products/ASC.Files/Server/Helpers/Global.cs b/products/ASC.Files/Server/Helpers/Global.cs index ec118be4db..470989724c 100644 --- a/products/ASC.Files/Server/Helpers/Global.cs +++ b/products/ASC.Files/Server/Helpers/Global.cs @@ -51,7 +51,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Constants = ASC.Core.Configuration.Constants; -using File = ASC.Files.Core.File; namespace ASC.Web.Files.Classes { @@ -279,16 +278,16 @@ namespace ASC.Web.Files.Classes Logger = options.Get("ASC.Files"); } - internal static readonly IDictionary ProjectsRootFolderCache = - new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ + internal static readonly IDictionary ProjectsRootFolderCache = + new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ - public object GetFolderProjects(IDaoFactory daoFactory) + public int GetFolderProjects(IDaoFactory daoFactory) { - if (CoreBaseSettings.Personal) return null; + if (CoreBaseSettings.Personal) return default; - if (WebItemManager[WebItemManager.ProjectsProductID].IsDisabled(WebItemSecurity, AuthContext)) return null; + if (WebItemManager[WebItemManager.ProjectsProductID].IsDisabled(WebItemSecurity, AuthContext)) return default; - var folderDao = daoFactory.FolderDao; + var folderDao = daoFactory.GetFolderDao(); if (!ProjectsRootFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var result)) { result = folderDao.GetFolderIDProjects(true); @@ -301,34 +300,22 @@ namespace ASC.Web.Files.Classes public T GetFolderProjects(IDaoFactory daoFactory) { - if (CoreBaseSettings.Personal) return default; - - if (WebItemManager[WebItemManager.ProjectsProductID].IsDisabled(WebItemSecurity, AuthContext)) return default; - - var folderDao = daoFactory.GetFolderDao(); - if (!ProjectsRootFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var result)) - { - result = folderDao.GetFolderIDProjects(true); - - ProjectsRootFolderCache[TenantManager.GetCurrentTenant().TenantId] = result; - } - - return (T)result; + return (T)Convert.ChangeType(GetFolderProjects(daoFactory), typeof(T)); } - internal static readonly IDictionary UserRootFolderCache = - new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ + internal static readonly IDictionary UserRootFolderCache = + new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ - public object GetFolderMy(FileMarker fileMarker, IDaoFactory daoFactory) + public int GetFolderMy(FileMarker fileMarker, IDaoFactory daoFactory) { - if (!AuthContext.IsAuthenticated) return 0; - if (UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) return 0; + if (!AuthContext.IsAuthenticated) return default; + if (UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) return default; var cacheKey = string.Format("my/{0}/{1}", TenantManager.GetCurrentTenant().TenantId, AuthContext.CurrentAccount.ID); if (!UserRootFolderCache.TryGetValue(cacheKey, out var myFolderId)) { - myFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, true); + myFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, true); if (!Equals(myFolderId, 0)) UserRootFolderCache[cacheKey] = myFolderId; } @@ -341,67 +328,49 @@ namespace ASC.Web.Files.Classes UserRootFolderCache.Remove(cacheKey); } - internal static readonly IDictionary CommonFolderCache = - new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ + internal static readonly IDictionary CommonFolderCache = + new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ - public object GetFolderCommon(FileMarker fileMarker, IDaoFactory daoFactory) - { - if (CoreBaseSettings.Personal) return null; - - if (!CommonFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var commonFolderId)) - { - commonFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, false); - if (!Equals(commonFolderId, 0)) - CommonFolderCache[TenantManager.GetCurrentTenant().TenantId] = commonFolderId; - } - return commonFolderId; - } public T GetFolderCommon(FileMarker fileMarker, IDaoFactory daoFactory) + { + return (T)Convert.ChangeType(GetFolderCommon(fileMarker, daoFactory), typeof(T)); + } + + public int GetFolderCommon(FileMarker fileMarker, IDaoFactory daoFactory) { if (CoreBaseSettings.Personal) return default; if (!CommonFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var commonFolderId)) { - commonFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, false); + commonFolderId = GetFolderIdAndProccessFirstVisit(fileMarker, daoFactory, false); if (!Equals(commonFolderId, 0)) CommonFolderCache[TenantManager.GetCurrentTenant().TenantId] = commonFolderId; } - return (T)commonFolderId; + return commonFolderId; } - internal static readonly IDictionary ShareFolderCache = - new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ + internal static readonly IDictionary ShareFolderCache = + new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ - public object GetFolderShare(IFolderDao folderDao) - { - if (CoreBaseSettings.Personal) return null; - if (IsOutsider) return null; - - if (!ShareFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var sharedFolderId)) - { - sharedFolderId = folderDao.GetFolderIDShare(true); - - if (!sharedFolderId.Equals(0)) - ShareFolderCache[TenantManager.GetCurrentTenant().TenantId] = sharedFolderId; - } - - return sharedFolderId; - } - - public T GetFolderShare(IFolderDao folderDao) + public int GetFolderShare(IDaoFactory daoFactory) { if (CoreBaseSettings.Personal) return default; if (IsOutsider) return default; if (!ShareFolderCache.TryGetValue(TenantManager.GetCurrentTenant().TenantId, out var sharedFolderId)) { - sharedFolderId = folderDao.GetFolderIDShare(true); + sharedFolderId = daoFactory.GetFolderDao().GetFolderIDShare(true); if (!sharedFolderId.Equals(default)) ShareFolderCache[TenantManager.GetCurrentTenant().TenantId] = sharedFolderId; } - return (T)sharedFolderId; + return sharedFolderId; + } + + public T GetFolderShare(IDaoFactory daoFactory) + { + return (T)Convert.ChangeType(GetFolderShare(daoFactory), typeof(T)); } internal static readonly IDictionary TrashFolderCache = @@ -463,61 +432,6 @@ namespace ASC.Web.Files.Classes return id; } - private object GetFolderIdAndProccessFirstVisit(FileMarker fileMarker, IDaoFactory daoFactory, bool my) - { - var folderDao = daoFactory.FolderDao; - var fileDao = daoFactory.FileDao; - - var id = my ? folderDao.GetFolderIDUser(false) : folderDao.GetFolderIDCommon(false); - - if (Equals(id, 0)) //TODO: think about 'null' - { - id = my ? folderDao.GetFolderIDUser(true) : folderDao.GetFolderIDCommon(true); - - //Copy start document - if (AdditionalWhiteLabelSettings.Instance(SettingsManager).StartDocsEnabled) - { - try - { - var storeTemplate = GlobalStore.GetStoreTemplate(); - - var culture = my ? UserManager.GetUsers(AuthContext.CurrentAccount.ID).GetCulture() : TenantManager.GetCurrentTenant().GetCulture(); - var path = FileConstant.StartDocPath + culture + "/"; - - if (!storeTemplate.IsDirectory(path)) - path = FileConstant.StartDocPath + "default/"; - path += my ? "my/" : "corporate/"; - - SaveStartDocument(fileMarker, folderDao, fileDao, id, path, storeTemplate); - } - catch (Exception ex) - { - Logger.Error(ex); - } - } - } - - return id; - } - - private void SaveStartDocument(FileMarker fileMarker, IFolderDao folderDao, IFileDao fileDao, object folderId, string path, IDataStore storeTemplate) - { - foreach (var file in storeTemplate.ListFilesRelative("", path, "*", false)) - { - SaveFile(fileMarker, fileDao, folderId, path + file, storeTemplate); - } - - foreach (var folderName in storeTemplate.ListDirectoriesRelative(path, false)) - { - var folder = ServiceProvider.GetService(); - folder.Title = folderName; - folder.ParentFolderID = folderId; - - var subFolderId = folderDao.SaveFolder(folder); - - SaveStartDocument(fileMarker, folderDao, fileDao, subFolderId, path + folderName + "/", storeTemplate); - } - } private void SaveStartDocument(FileMarker fileMarker, IFolderDao folderDao, IFileDao fileDao, T folderId, string path, IDataStore storeTemplate) { @@ -538,30 +452,6 @@ namespace ASC.Web.Files.Classes } } - private void SaveFile(FileMarker fileMarker, IFileDao fileDao, object folder, string filePath, IDataStore storeTemp) - { - using var stream = storeTemp.GetReadStream("", filePath); - var fileName = Path.GetFileName(filePath); - var file = ServiceProvider.GetService(); - - file.Title = fileName; - file.ContentLength = stream.CanSeek ? stream.Length : storeTemp.GetFileSize("", filePath); - file.FolderID = folder; - file.Comment = FilesCommonResource.CommentCreate; - - stream.Position = 0; - try - { - file = fileDao.SaveFile(file, stream); - - fileMarker.MarkAsNew(file); - } - catch (Exception ex) - { - Logger.Error(ex); - } - } - private void SaveFile(FileMarker fileMarker, IFileDao fileDao, T folder, string filePath, IDataStore storeTemp) { using var stream = storeTemp.GetReadStream("", filePath); @@ -578,7 +468,7 @@ namespace ASC.Web.Files.Classes { file = fileDao.SaveFile(file, stream); - fileMarker.MarkAsNew(file); + fileMarker.MarkAsNew(file); } catch (Exception ex) { @@ -605,56 +495,26 @@ namespace ASC.Web.Files.Classes GlobalFolder = globalFolder; } - public object FolderProjects - { - get - { - return GlobalFolder.GetFolderProjects(DaoFactory); - } - } - public T GetFolderProjects() - { - return GlobalFolder.GetFolderProjects(DaoFactory); - } + public int FolderProjects => GlobalFolder.GetFolderProjects(DaoFactory); + public int FolderCommon => GlobalFolder.GetFolderCommon(FileMarker, DaoFactory); + public int FolderMy => GlobalFolder.GetFolderMy(FileMarker, DaoFactory); - public object FolderCommon - { - get - { - return GlobalFolder.GetFolderCommon(FileMarker, DaoFactory); - } - } + public T GetFolderMy() => (T)Convert.ChangeType(FolderMy, typeof(T)); + public T GetFolderCommon() => (T)Convert.ChangeType(FolderCommon, typeof(T)); + public T GetFolderProjects() => (T)Convert.ChangeType(FolderProjects, typeof(T)); - public T GetFolderCommon() + public void SetFolderMy(T val) { - return GlobalFolder.GetFolderCommon(FileMarker, DaoFactory); - } - - public object FolderMy - { - get - { - return GlobalFolder.GetFolderMy(FileMarker, DaoFactory); - } - set - { - GlobalFolder.SetFolderMy(value); - } - } - - public object FolderShare - { - get - { - return GlobalFolder.GetFolderShare(DaoFactory.FolderDao); - } + GlobalFolder.SetFolderMy(val); } public T GetFolderShare() { - return GlobalFolder.GetFolderShare(DaoFactory.GetFolderDao()); + return (T)Convert.ChangeType(FolderShare, typeof(T)); } + public int FolderShare => GlobalFolder.GetFolderShare(DaoFactory); + public object FolderTrash { get diff --git a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs index b6465ebaca..3217e06bab 100644 --- a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs @@ -303,7 +303,7 @@ namespace ASC.Web.Files return; } - if (!readLink && !FileSecurity.CanRead(file)) + if (!readLink && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -555,11 +555,24 @@ namespace ASC.Web.Files } private void StreamFile(HttpContext context) + { + var q = context.Request.Query[FilesLinkUtility.FileId]; + + if (int.TryParse(q, out var id)) + { + StreamFile(context, id); + } + else + { + StreamFile(context, q); + } + } + + private void StreamFile(HttpContext context, T id) { try { - var fileDao = DaoFactory.FileDao; - var id = context.Request.Query[FilesLinkUtility.FileId]; + var fileDao = DaoFactory.GetFileDao(); if (!int.TryParse(context.Request.Query[FilesLinkUtility.Version].FirstOrDefault() ?? "", out var version)) { version = 0; @@ -572,7 +585,7 @@ namespace ASC.Web.Files if (linkRight == FileShare.Restrict && !SecurityContext.IsAuthenticated) { var auth = context.Request.Query[FilesLinkUtility.AuthKey]; - var validateResult = EmailValidationKeyProvider.ValidateEmailKey(id + version, auth.FirstOrDefault() ?? "", Global.StreamUrlExpire); + var validateResult = EmailValidationKeyProvider.ValidateEmailKey(id.ToString() + version, auth.FirstOrDefault() ?? "", Global.StreamUrlExpire); if (validateResult != EmailValidationKeyProvider.ValidationResult.Ok) { var exc = new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException); @@ -643,7 +656,7 @@ namespace ASC.Web.Files return; } - if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) + if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -835,11 +848,24 @@ namespace ASC.Web.Files } private void DifferenceFile(HttpContext context) + { + var q = context.Request.Query[FilesLinkUtility.FileId]; + + if (int.TryParse(q, out var id)) + { + DifferenceFile(context, id); + } + else + { + DifferenceFile(context, q); + } + } + + private void DifferenceFile(HttpContext context, T id) { try { - var fileDao = DaoFactory.FileDao; - var id = context.Request.Query[FilesLinkUtility.FileId]; + var fileDao = DaoFactory.GetFileDao(); int.TryParse(context.Request.Query[FilesLinkUtility.Version].FirstOrDefault() ?? "", out var version); var doc = context.Request.Query[FilesLinkUtility.DocShareKey]; @@ -847,7 +873,7 @@ namespace ASC.Web.Files if (linkRight == FileShare.Restrict && !SecurityContext.IsAuthenticated) { var auth = context.Request.Query[FilesLinkUtility.AuthKey].FirstOrDefault(); - var validateResult = EmailValidationKeyProvider.ValidateEmailKey(id + version, auth ?? "", Global.StreamUrlExpire); + var validateResult = EmailValidationKeyProvider.ValidateEmailKey(id.ToString() + version, auth ?? "", Global.StreamUrlExpire); if (validateResult != EmailValidationKeyProvider.ValidationResult.Ok) { var exc = new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException); @@ -876,7 +902,7 @@ namespace ASC.Web.Files return; } - if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) + if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -925,17 +951,27 @@ namespace ASC.Web.Files private void CreateFile(HttpContext context) { - var responseMessage = context.Request.Query["response"] == "message"; var folderId = context.Request.Query[FilesLinkUtility.FolderId].FirstOrDefault(); if (string.IsNullOrEmpty(folderId)) - folderId = GlobalFolderHelper.FolderMy.ToString(); - Folder folder; + { + CreateFile(context, GlobalFolderHelper.FolderMy); + } + else + { + CreateFile(context, folderId); + } + } - var folderDao = DaoFactory.FolderDao; + private void CreateFile(HttpContext context, T folderId) + { + var responseMessage = context.Request.Query["response"] == "message"; + Folder folder; + + var folderDao = DaoFactory.GetFolderDao(); folder = folderDao.GetFolder(folderId); if (folder == null) throw new HttpException((int)HttpStatusCode.NotFound, FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanCreate(folder)) throw new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException_Create); + if (!FileSecurity.CanCreate(folder)) throw new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException_Create); File file; var fileUri = context.Request.Query[FilesLinkUtility.FileUri]; @@ -964,7 +1000,7 @@ namespace ASC.Web.Files return; } - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); if (responseMessage) { @@ -978,7 +1014,7 @@ namespace ASC.Web.Files : (FilesLinkUtility.GetFileWebEditorUrl(file.ID) + "#message/" + HttpUtility.UrlEncode(string.Format(FilesCommonResource.MessageFileCreated, folder.Title)))); } - private File CreateFileFromTemplate(Folder folder, string fileTitle, string docType) + private File CreateFileFromTemplate(Folder folder, string fileTitle, string docType) { var storeTemplate = GlobalStore.GetStoreTemplate(); @@ -987,7 +1023,7 @@ namespace ASC.Web.Files var fileExt = FileUtility.InternalExtension[FileType.Document]; if (!string.IsNullOrEmpty(docType)) { - var tmpFileType = Services.DocumentService.Configuration.DocType.FirstOrDefault(r => r.Value.Equals(docType, StringComparison.OrdinalIgnoreCase)); + var tmpFileType = Configuration.DocType.FirstOrDefault(r => r.Value.Equals(docType, StringComparison.OrdinalIgnoreCase)); FileUtility.InternalExtension.TryGetValue(tmpFileType.Key, out var tmpFileExt); if (!string.IsNullOrEmpty(tmpFileExt)) fileExt = tmpFileExt; @@ -1009,23 +1045,23 @@ namespace ASC.Web.Files fileTitle += fileExt; } - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.Title = fileTitle; file.FolderID = folder.ID; file.Comment = FilesCommonResource.CommentCreate; - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var stream = storeTemplate.GetReadStream("", templatePath); file.ContentLength = stream.CanSeek ? stream.Length : storeTemplate.GetFileSize(templatePath); return fileDao.SaveFile(file, stream); } - private File CreateFileFromUri(Folder folder, string fileUri, string fileTitle) + private File CreateFileFromUri(Folder folder, string fileUri, string fileTitle) { if (string.IsNullOrEmpty(fileTitle)) fileTitle = Path.GetFileName(HttpUtility.UrlDecode(fileUri)); - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.Title = fileTitle; file.FolderID = folder.ID; file.Comment = FilesCommonResource.CommentCreate; @@ -1038,7 +1074,7 @@ namespace ASC.Web.Files ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; } - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var fileStream = new ResponseStream(req.GetResponse()); file.ContentLength = fileStream.Length; @@ -1046,6 +1082,21 @@ namespace ASC.Web.Files } private void Redirect(HttpContext context) + { + var q = context.Request.Query[FilesLinkUtility.FileId]; + var q1 = context.Request.Query[FilesLinkUtility.FolderId]; + + if (int.TryParse(q, out var fileId) && int.TryParse(q1, out var folderId)) + { + Redirect(context, fileId, folderId); + } + else + { + Redirect(context, q, q1); + } + } + + private void Redirect(HttpContext context, T folderId, T fileId) { if (!SecurityContext.AuthenticateMe(CookiesManager.GetCookies(CookiesType.AuthKey))) { @@ -1053,8 +1104,7 @@ namespace ASC.Web.Files return; } var urlRedirect = string.Empty; - var folderId = context.Request.Query[FilesLinkUtility.FolderId]; - if (!string.IsNullOrEmpty(folderId)) + if (folderId != null) { try { @@ -1066,10 +1116,9 @@ namespace ASC.Web.Files } } - var fileId = context.Request.Query[FilesLinkUtility.FileId]; - if (!string.IsNullOrEmpty(fileId)) + if (fileId != null) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var file = fileDao.GetFile(fileId); if (file == null) { diff --git a/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs b/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs index 8ac968e37e..617187ab01 100644 --- a/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs +++ b/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs @@ -98,19 +98,19 @@ namespace ASC.Web.Files.Configuration ThirdpartyConfiguration = thirdpartyConfiguration; } - public IEnumerable SearchFiles(string text) + public IEnumerable> SearchFiles(string text) { var security = FileSecurity; - var fileDao = DaoFactory.FileDao; - return fileDao.Search(text).Where(security.CanRead); + var fileDao = DaoFactory.GetFileDao(); + return fileDao.Search(text).Where(security.CanRead); } - public IEnumerable SearchFolders(string text) + public IEnumerable> SearchFolders(string text) { var security = FileSecurity; - IEnumerable result; - var folderDao = DaoFactory.FolderDao; - result = folderDao.Search(text).Where(security.CanRead); + IEnumerable> result; + var folderDao = DaoFactory.GetFolderDao(); + result = folderDao.Search(text).Where(security.CanRead); if (ThirdpartyConfiguration.SupportInclusion && (Global.IsAdministrator || FilesSettingsHelper.EnableThirdParty)) @@ -119,12 +119,12 @@ namespace ASC.Web.Files.Configuration if (!Equals(id, 0)) { var folderMy = folderDao.GetFolder(id); - result = result.Concat(EntryManager.GetThirpartyFolders(folderMy, text)); + //result = result.Concat(EntryManager.GetThirpartyFolders(folderMy, text)); } id = GlobalFolderHelper.FolderCommon; var folderCommon = folderDao.GetFolder(id); - result = result.Concat(EntryManager.GetThirpartyFolders(folderCommon, text)); + //result = result.Concat(EntryManager.GetThirpartyFolders(folderCommon, text)); } return result; @@ -132,7 +132,7 @@ namespace ASC.Web.Files.Configuration public SearchResultItem[] Search(string text) { - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var result = SearchFiles(text) .Select(r => new SearchResultItem { diff --git a/products/ASC.Files/Server/Model/FileOperationWraper.cs b/products/ASC.Files/Server/Model/FileOperationWraper.cs index b52ff4ccad..1dc4ed05ac 100644 --- a/products/ASC.Files/Server/Model/FileOperationWraper.cs +++ b/products/ASC.Files/Server/Model/FileOperationWraper.cs @@ -132,7 +132,7 @@ namespace ASC.Api.Documents CommonLinkUtility = commonLinkUtility; } - public FileOperationWraper Get(FileOperationResult o) + public FileOperationWraper Get(FileOperationResult o) { var result = new FileOperationWraper { @@ -147,17 +147,25 @@ namespace ASC.Api.Documents if (!string.IsNullOrEmpty(o.Result) && result.OperationType != FileOperationType.Delete) { var arr = o.Result.Split(':'); - var folders = arr.Where(s => s.StartsWith("folder_")).Select(s => s.Substring(7)); + var folders = arr + .Where(s => s.StartsWith("folder_")) + .Select(s => s.Substring(7)) + .Select(r => (T)Convert.ChangeType(r, typeof(T))); + if (folders.Any()) { - var folderDao = DaoFactory.FolderDao; - result.Folders = folderDao.GetFolders(folders.ToArray()).Select(FolderWrapperHelper.Get).ToList(); + var folderDao = DaoFactory.GetFolderDao(); + result.Folders = folderDao.GetFolders(folders.ToArray()).Select(r => FolderWrapperHelper.Get(r)).ToList(); } - var files = arr.Where(s => s.StartsWith("file_")).Select(s => s.Substring(5)); + var files = arr + .Where(s => s.StartsWith("file_")) + .Select(s => s.Substring(5)) + .Select(r => (T)Convert.ChangeType(r, typeof(T))); + if (files.Any()) { - var fileDao = DaoFactory.FileDao; - result.Files = fileDao.GetFiles(files.ToArray()).Select(FilesWrapperHelper.Get).ToList(); + var fileDao = DaoFactory.GetFileDao(); + result.Files = fileDao.GetFiles(files.ToArray()).Select(r => FilesWrapperHelper.Get(r)).ToList(); } if (result.OperationType == FileOperationType.Download) diff --git a/products/ASC.Files/Server/Model/FileWrapper.cs b/products/ASC.Files/Server/Model/FileWrapper.cs index da38e2a061..a14143df3d 100644 --- a/products/ASC.Files/Server/Model/FileWrapper.cs +++ b/products/ASC.Files/Server/Model/FileWrapper.cs @@ -39,7 +39,6 @@ using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Utility; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; namespace ASC.Api.Documents @@ -176,7 +175,7 @@ namespace ASC.Api.Documents FileUtility = fileUtility; } - public FileWrapper Get(File file) + public FileWrapper Get(File file) { var result = Get(file); result.FolderId = file.FolderID; @@ -184,9 +183,9 @@ namespace ASC.Api.Documents && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { result.RootFolderType = FolderType.SHARE; - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var parentFolder = folderDao.GetFolder(file.FolderID); - if (!FileSecurity.CanRead(parentFolder)) + if (!FileSecurity.CanRead(parentFolder)) { result.FolderId = GlobalFolderHelper.FolderShare; } diff --git a/products/ASC.Files/Server/Model/FolderContentWrapper.cs b/products/ASC.Files/Server/Model/FolderContentWrapper.cs index 71e84909e5..61fa258933 100644 --- a/products/ASC.Files/Server/Model/FolderContentWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderContentWrapper.cs @@ -119,12 +119,12 @@ namespace ASC.Api.Documents FolderWrapperHelper = folderWrapperHelper; } - public FolderContentWrapper Get(DataWrapper folderItems, int startIndex) + public FolderContentWrapper Get(DataWrapper folderItems, int startIndex) { var result = new FolderContentWrapper { - Files = folderItems.Entries.OfType().Select(FileWrapperHelper.Get).ToList(), - Folders = folderItems.Entries.OfType().Select(FolderWrapperHelper.Get).ToList(), + Files = folderItems.Entries.OfType>().Select(FileWrapperHelper.Get).ToList(), + Folders = folderItems.Entries.OfType>().Select(FolderWrapperHelper.Get).ToList(), PathParts = folderItems.FolderPathParts, StartIndex = startIndex }; diff --git a/products/ASC.Files/Server/Model/FolderWrapper.cs b/products/ASC.Files/Server/Model/FolderWrapper.cs index 3db69610d5..fa78a82cd1 100644 --- a/products/ASC.Files/Server/Model/FolderWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderWrapper.cs @@ -116,7 +116,7 @@ namespace ASC.Api.Documents GlobalFolderHelper = globalFolderHelper; } - public FolderWrapper Get(Folder folder) + public FolderWrapper Get(Folder folder) { var result = Get(folder); result.ParentId = folder.ParentFolderID; @@ -125,9 +125,9 @@ namespace ASC.Api.Documents { result.RootFolderType = FolderType.SHARE; - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var parentFolder = folderDao.GetFolder(folder.ParentFolderID); - if (!FileSecurity.CanRead(parentFolder)) + if (!FileSecurity.CanRead(parentFolder)) result.ParentId = GlobalFolderHelper.FolderShare; } diff --git a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs index d2fab72044..e3173b19bf 100644 --- a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs +++ b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs @@ -58,17 +58,20 @@ using ASC.Web.Studio.Utility; using Microsoft.Extensions.DependencyInjection; -using static ASC.Web.Files.Services.DocumentService.Configuration; -using static ASC.Web.Files.Services.DocumentService.Configuration.DocumentConfig; -using static ASC.Web.Files.Services.DocumentService.Configuration.EditorConfiguration; -using static ASC.Web.Files.Services.DocumentService.Configuration.EditorConfiguration.CustomizationConfig; - using File = ASC.Files.Core.File; namespace ASC.Web.Files.Services.DocumentService { + public enum EditorType + { + Desktop, + Mobile, + Embedded, + External, + } + [DataContract(Name = "editorConfig", Namespace = "")] - public class Configuration + public class Configuration { public static readonly Dictionary DocType = new Dictionary { @@ -77,24 +80,16 @@ namespace ASC.Web.Files.Services.DocumentService { FileType.Presentation, "presentation" } }; - public enum EditorType - { - Desktop, - Mobile, - Embedded, - External, - } - private FileType _fileTypeCache = FileType.Unknown; public Configuration( - File file, + File file, IServiceProvider serviceProvider ) { - Document = serviceProvider.GetService(); + Document = serviceProvider.GetService>(); Document.Info.File = file; - EditorConfig = serviceProvider.GetService(); + EditorConfig = serviceProvider.GetService>(); EditorConfig.SetConfiguration(this); } @@ -107,7 +102,7 @@ namespace ASC.Web.Files.Services.DocumentService #region Property [DataMember(Name = "document")] - public DocumentConfig Document; + public DocumentConfig Document; [DataMember(Name = "documentType")] public string DocumentType @@ -121,7 +116,7 @@ namespace ASC.Web.Files.Services.DocumentService } [DataMember(Name = "editorConfig")] - public EditorConfiguration EditorConfig; + public EditorConfiguration EditorConfig; [DataMember(Name = "token", EmitDefaultValue = false)] public string Token; @@ -133,7 +128,7 @@ namespace ASC.Web.Files.Services.DocumentService get { return Type.ToString().ToLower(); } } - private FileType GetFileType + internal FileType GetFileType { set { } get @@ -149,785 +144,775 @@ namespace ASC.Web.Files.Services.DocumentService #endregion - public static string Serialize(Configuration configuration) + public static string Serialize(Configuration configuration) { using var ms = new MemoryStream(); - var serializer = new DataContractJsonSerializer(typeof(Configuration)); + var serializer = new DataContractJsonSerializer(typeof(Configuration)); serializer.WriteObject(ms, configuration); ms.Seek(0, SeekOrigin.Begin); return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length); } + } + #region Nested Classes - #region Nested Classes + [DataContract(Name = "document", Namespace = "")] + public class DocumentConfig + { + public string SharedLinkKey; - [DataContract(Name = "document", Namespace = "")] - public class DocumentConfig + public DocumentConfig(DocumentServiceConnector documentServiceConnector, PathProvider pathProvider, InfoConfig infoConfig) { - public string SharedLinkKey; - - public DocumentConfig(DocumentServiceConnector documentServiceConnector, PathProvider pathProvider, InfoConfig infoConfig) - { - Info = infoConfig; - Permissions = new PermissionsConfig(); - DocumentServiceConnector = documentServiceConnector; - PathProvider = pathProvider; - } - - private string _key = string.Empty; - private string _fileUri; - private string _title = null; - - - [DataMember(Name = "fileType")] - public string FileType - { - set { } - get { return Info.File.ConvertedExtension.Trim('.'); } - } - - [DataMember(Name = "info")] - public InfoConfig Info; - - [DataMember(Name = "key")] - public string Key - { - set { _key = value; } - get { return DocumentServiceConnector.GenerateRevisionId(_key); } - } - - [DataMember(Name = "permissions")] - public PermissionsConfig Permissions; - - [DataMember(Name = "title")] - public string Title - { - set { _title = value; } - get { return _title ?? Info.File.Title; } - } - - [DataMember(Name = "url")] - public string Url - { - set { _fileUri = DocumentServiceConnector.ReplaceCommunityAdress(value); } - get - { - if (!string.IsNullOrEmpty(_fileUri)) - return _fileUri; - var last = Permissions.Edit || Permissions.Review || Permissions.Comment; - _fileUri = DocumentServiceConnector.ReplaceCommunityAdress(PathProvider.GetFileStreamUrl(Info.File, SharedLinkKey, last)); - return _fileUri; - } - } - - public DocumentServiceConnector DocumentServiceConnector { get; } - public PathProvider PathProvider { get; } - - - #region Nested Classes - - [DataContract(Name = "info", Namespace = "")] - public class InfoConfig - { - public File File; - - public EditorType Type = EditorType.Desktop; - private string _breadCrumbs; - - public InfoConfig(BreadCrumbsManager breadCrumbsManager, FileSharing fileSharing) - { - BreadCrumbsManager = breadCrumbsManager; - FileSharing = fileSharing; - } - - [Obsolete("Use owner (since v5.4)")] - [DataMember(Name = "author")] - public string Aouthor - { - set { } - get { return File.CreateByString; } - } - - [Obsolete("Use uploaded (since v5.4)")] - [DataMember(Name = "created")] - public string Created - { - set { } - get { return File.CreateOnString; } - } - - [DataMember(Name = "folder", EmitDefaultValue = false)] - public string Folder - { - set { } - get - { - if (Type == EditorType.Embedded || Type == EditorType.External) return null; - if (string.IsNullOrEmpty(_breadCrumbs)) - { - const string crumbsSeporator = " \\ "; - - var breadCrumbsList = BreadCrumbsManager.GetBreadCrumbs(File.FolderID); - _breadCrumbs = string.Join(crumbsSeporator, breadCrumbsList.Select(folder => folder.Title).ToArray()); - } - - return _breadCrumbs; - } - } - - [DataMember(Name = "owner")] - public string Owner - { - set { } - get { return File.CreateByString; } - } - - [DataMember(Name = "uploaded")] - public string Uploaded - { - set { } - get { return File.CreateOnString; } - } - - [DataMember(Name = "sharingSettings", EmitDefaultValue = false)] - public ItemList SharingSettings - { - set { } - get - { - if (Type == EditorType.Embedded - || Type == EditorType.External - || !FileSharing.CanSetAccess(File)) return null; - - try - { - return FileSharing.GetSharedInfoShort(File.UniqID); - } - catch - { - return null; - } - } - } - - public BreadCrumbsManager BreadCrumbsManager { get; } - public FileSharing FileSharing { get; } - } - - [DataContract(Name = "permissions", Namespace = "")] - public class PermissionsConfig - { - [Obsolete("Since DS v5.5")] - [DataMember(Name = "changeHistory")] - public bool ChangeHistory = false; - - [DataMember(Name = "comment")] - public bool Comment = true; - - [DataMember(Name = "download")] - public bool Download = true; - - [DataMember(Name = "edit")] - public bool Edit = true; - - [DataMember(Name = "fillForms")] - public bool FillForms = true; - - [DataMember(Name = "print")] - public bool Print = true; - - [DataMember(Name = "rename")] - public bool Rename = false; - - [DataMember(Name = "review")] - public bool Review = true; - } - - #endregion + Info = infoConfig; + Permissions = new PermissionsConfig(); + DocumentServiceConnector = documentServiceConnector; + PathProvider = pathProvider; } - [DataContract(Name = "editorConfig", Namespace = "")] - public class EditorConfiguration + private string _key = string.Empty; + private string _fileUri; + private string _title = null; + + + [DataMember(Name = "fileType")] + public string FileType { - public EditorConfiguration( - UserManager userManager, - AuthContext authContext, - DisplayUserSettingsHelper displayUserSettingsHelper, - FilesLinkUtility filesLinkUtility, - BaseCommonLinkUtility baseCommonLinkUtility, - PluginsConfig pluginsConfig, - EmbeddedConfig embeddedConfig, - CustomizationConfig customizationConfig) - { - UserManager = userManager; - AuthContext = authContext; - FilesLinkUtility = filesLinkUtility; - BaseCommonLinkUtility = baseCommonLinkUtility; - Customization = customizationConfig; - Plugins = pluginsConfig; - Embedded = embeddedConfig; - _userInfo = userManager.GetUsers(authContext.CurrentAccount.ID); + set { } + get { return Info.File.ConvertedExtension.Trim('.'); } + } - User = _userInfo.ID.Equals(ASC.Core.Configuration.Constants.Guest.ID) - ? new UserConfig - { - Id = Guid.NewGuid().ToString(), - Name = FilesCommonResource.Guest, - } - : new UserConfig - { - Id = _userInfo.ID.ToString(), - Name = _userInfo.DisplayUserName(false, displayUserSettingsHelper), - }; + [DataMember(Name = "info")] + public InfoConfig Info; + + [DataMember(Name = "key")] + public string Key + { + set { _key = value; } + get { return DocumentServiceConnector.GenerateRevisionId(_key); } + } + + [DataMember(Name = "permissions")] + public PermissionsConfig Permissions; + + [DataMember(Name = "title")] + public string Title + { + set { _title = value; } + get { return _title ?? Info.File.Title; } + } + + [DataMember(Name = "url")] + public string Url + { + set { _fileUri = DocumentServiceConnector.ReplaceCommunityAdress(value); } + get + { + if (!string.IsNullOrEmpty(_fileUri)) + return _fileUri; + var last = Permissions.Edit || Permissions.Review || Permissions.Comment; + _fileUri = DocumentServiceConnector.ReplaceCommunityAdress(PathProvider.GetFileStreamUrl(Info.File, SharedLinkKey, last)); + return _fileUri; } + } - public bool ModeWrite = false; + public DocumentServiceConnector DocumentServiceConnector { get; } + public PathProvider PathProvider { get; } + } - private Configuration _configuration; + [DataContract(Name = "info", Namespace = "")] + public class InfoConfig + { + public File File; - internal void SetConfiguration(Configuration configuration) + public EditorType Type = EditorType.Desktop; + private string _breadCrumbs; + + public InfoConfig(BreadCrumbsManager breadCrumbsManager, FileSharing fileSharing) + { + BreadCrumbsManager = breadCrumbsManager; + FileSharing = fileSharing; + } + + [Obsolete("Use owner (since v5.4)")] + [DataMember(Name = "author")] + public string Aouthor + { + set { } + get { return File.CreateByString; } + } + + [Obsolete("Use uploaded (since v5.4)")] + [DataMember(Name = "created")] + public string Created + { + set { } + get { return File.CreateOnString; } + } + + [DataMember(Name = "folder", EmitDefaultValue = false)] + public string Folder + { + set { } + get { - _configuration = configuration; - Customization.SetConfiguration(_configuration); - } - - private readonly UserInfo _userInfo; - private EmbeddedConfig _embeddedConfig; - - [DataMember(Name = "actionLink", EmitDefaultValue = false)] - public ActionLinkConfig ActionLink; - - public string ActionLinkString - { - get { return null; } - set + if (Type == EditorType.Embedded || Type == EditorType.External) return null; + if (string.IsNullOrEmpty(_breadCrumbs)) { - try - { - using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(value))) - { - var serializer = new DataContractJsonSerializer(typeof(ActionLinkConfig)); - ActionLink = (ActionLinkConfig)serializer.ReadObject(ms); - } - } - catch (Exception) - { - ActionLink = null; - } - } - } + const string crumbsSeporator = " \\ "; - [DataMember(Name = "callbackUrl", EmitDefaultValue = false)] - public string CallbackUrl; - - [DataMember(Name = "createUrl", EmitDefaultValue = false)] - public string CreateUrl - { - set { } - get - { - if (_configuration.Document.Info.Type != EditorType.Desktop) return null; - if (!AuthContext.IsAuthenticated || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) return null; - - return GetCreateUrl(_configuration.GetFileType); - } - } - - [DataMember(Name = "plugins", EmitDefaultValue = false)] - public PluginsConfig Plugins; - - [DataMember(Name = "customization", EmitDefaultValue = false)] - public CustomizationConfig Customization; - - [DataMember(Name = "embedded", EmitDefaultValue = false)] - public EmbeddedConfig Embedded - { - set { _embeddedConfig = value; } - get { return _configuration.Document.Info.Type == EditorType.Embedded ? _embeddedConfig : null; } - } - - [DataMember(Name = "fileChoiceUrl", EmitDefaultValue = false)] - public string FileChoiceUrl; - - [DataMember(Name = "lang")] - public string Lang - { - set { } - get { return _userInfo.GetCulture().Name; } - } - - //todo: remove old feild after release 5.2+ - [DataMember(Name = "mergeFolderUrl", EmitDefaultValue = false)] - public string MergeFolderUrl; - - [DataMember(Name = "mode")] - public string Mode - { - set { } - get { return ModeWrite ? "edit" : "view"; } - } - - public UserManager UserManager { get; } - public AuthContext AuthContext { get; } - public FilesLinkUtility FilesLinkUtility { get; } - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - - [DataMember(Name = "saveAsUrl", EmitDefaultValue = false)] - public string SaveAsUrl; - - [DataMember(Name = "sharingSettingsUrl", EmitDefaultValue = false)] - public string SharingSettingsUrl; - - [DataMember(Name = "user")] - public UserConfig User; - - private string GetCreateUrl(FileType fileType) - { - string title; - switch (fileType) - { - case FileType.Document: - title = FilesJSResource.TitleNewFileText; - break; - case FileType.Spreadsheet: - title = FilesJSResource.TitleNewFileSpreadsheet; - break; - case FileType.Presentation: - title = FilesJSResource.TitleNewFilePresentation; - break; - default: - return null; + var breadCrumbsList = BreadCrumbsManager.GetBreadCrumbs(File.FolderID); + _breadCrumbs = string.Join(crumbsSeporator, breadCrumbsList.Select(folder => folder.Title).ToArray()); } - DocType.TryGetValue(fileType, out var documentType); - - return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath) - + "?" + FilesLinkUtility.Action + "=create" - + "&doctype=" + documentType - + "&" + FilesLinkUtility.FileTitle + "=" + HttpUtility.UrlEncode(title); + return _breadCrumbs; } + } - #region Nested Classes + [DataMember(Name = "owner")] + public string Owner + { + set { } + get { return File.CreateByString; } + } - [DataContract(Name = "actionLink", Namespace = "")] - public class ActionLinkConfig + [DataMember(Name = "uploaded")] + public string Uploaded + { + set { } + get { return File.CreateOnString; } + } + + [DataMember(Name = "sharingSettings", EmitDefaultValue = false)] + public ItemList SharingSettings + { + set { } + get { - [DataMember(Name = "action", EmitDefaultValue = false)] - public ActionConfig Action; + if (Type == EditorType.Embedded + || Type == EditorType.External + || !FileSharing.CanSetAccess(File)) return null; - - [DataContract(Name = "action", Namespace = "")] - public class ActionConfig + try { - [DataMember(Name = "type", EmitDefaultValue = false)] - public string Type; - - [DataMember(Name = "data", EmitDefaultValue = false)] - public string Data; + return FileSharing.GetSharedInfoShort(File.UniqID); } - - - public static string Serialize(ActionLinkConfig actionLinkConfig) + catch { - using (var ms = new MemoryStream()) + return null; + } + } + } + + public BreadCrumbsManager BreadCrumbsManager { get; } + public FileSharing FileSharing { get; } + } + + [DataContract(Name = "permissions", Namespace = "")] + public class PermissionsConfig + { + [Obsolete("Since DS v5.5")] + [DataMember(Name = "changeHistory")] + public bool ChangeHistory = false; + + [DataMember(Name = "comment")] + public bool Comment = true; + + [DataMember(Name = "download")] + public bool Download = true; + + [DataMember(Name = "edit")] + public bool Edit = true; + + [DataMember(Name = "fillForms")] + public bool FillForms = true; + + [DataMember(Name = "print")] + public bool Print = true; + + [DataMember(Name = "rename")] + public bool Rename = false; + + [DataMember(Name = "review")] + public bool Review = true; + } + + [DataContract(Name = "editorConfig", Namespace = "")] + public class EditorConfiguration + { + public EditorConfiguration( + UserManager userManager, + AuthContext authContext, + DisplayUserSettingsHelper displayUserSettingsHelper, + FilesLinkUtility filesLinkUtility, + BaseCommonLinkUtility baseCommonLinkUtility, + PluginsConfig pluginsConfig, + EmbeddedConfig embeddedConfig, + CustomizationConfig customizationConfig) + { + UserManager = userManager; + AuthContext = authContext; + FilesLinkUtility = filesLinkUtility; + BaseCommonLinkUtility = baseCommonLinkUtility; + Customization = customizationConfig; + Plugins = pluginsConfig; + Embedded = embeddedConfig; + _userInfo = userManager.GetUsers(authContext.CurrentAccount.ID); + + User = _userInfo.ID.Equals(ASC.Core.Configuration.Constants.Guest.ID) + ? new UserConfig + { + Id = Guid.NewGuid().ToString(), + Name = FilesCommonResource.Guest, + } + : new UserConfig + { + Id = _userInfo.ID.ToString(), + Name = _userInfo.DisplayUserName(false, displayUserSettingsHelper), + }; + } + + public bool ModeWrite = false; + + private Configuration _configuration; + + internal void SetConfiguration(Configuration configuration) + { + _configuration = configuration; + Customization.SetConfiguration(_configuration); + } + + private readonly UserInfo _userInfo; + private EmbeddedConfig _embeddedConfig; + + [DataMember(Name = "actionLink", EmitDefaultValue = false)] + public ActionLinkConfig ActionLink; + + public string ActionLinkString + { + get { return null; } + set + { + try + { + using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(value))) { var serializer = new DataContractJsonSerializer(typeof(ActionLinkConfig)); - serializer.WriteObject(ms, actionLinkConfig); - ms.Seek(0, SeekOrigin.Begin); - return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length); + ActionLink = (ActionLinkConfig)serializer.ReadObject(ms); } } + catch (Exception) + { + ActionLink = null; + } } - - [DataContract(Name = "embedded", Namespace = "")] - public class EmbeddedConfig - { - public string ShareLinkParam; - - [DataMember(Name = "embedUrl", EmitDefaultValue = false)] - public string EmbedUrl - { - set { } - get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FilesBaseAbsolutePath + FilesLinkUtility.EditorPage + "?" + FilesLinkUtility.Action + "=embedded" + ShareLinkParam); } - } - - [DataMember(Name = "saveUrl", EmitDefaultValue = false)] - public string SaveUrl - { - set { } - get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath + "?" + FilesLinkUtility.Action + "=download" + ShareLinkParam); } - } - - [DataMember(Name = "shareUrl", EmitDefaultValue = false)] - public string ShareUrl - { - set { } - get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FilesBaseAbsolutePath + FilesLinkUtility.EditorPage + "?" + FilesLinkUtility.Action + "=view" + ShareLinkParam); } - } - - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - public FilesLinkUtility FilesLinkUtility { get; } - - [DataMember(Name = "toolbarDocked")] - public string ToolbarDocked = "top"; - - public EmbeddedConfig(BaseCommonLinkUtility baseCommonLinkUtility, FilesLinkUtility filesLinkUtility) - { - BaseCommonLinkUtility = baseCommonLinkUtility; - FilesLinkUtility = filesLinkUtility; - } - } - - [DataContract(Name = "plugins", Namespace = "")] - public class PluginsConfig - { - [DataMember(Name = "pluginsData", EmitDefaultValue = false)] - public string[] PluginsData - { - set { } - get - { - var plugins = new List(); - - var easyBibHelper = ConsumerFactory.Get(); - if (!string.IsNullOrEmpty(easyBibHelper.AppKey)) - { - plugins.Add(BaseCommonLinkUtility.GetFullAbsolutePath("ThirdParty/plugin/easybib/config.json")); - } - - var wordpressLoginProvider = ConsumerFactory.Get(); - if (!string.IsNullOrEmpty(wordpressLoginProvider.ClientID) && - !string.IsNullOrEmpty(wordpressLoginProvider.ClientSecret) && - !string.IsNullOrEmpty(wordpressLoginProvider.RedirectUri)) - { - plugins.Add(BaseCommonLinkUtility.GetFullAbsolutePath("ThirdParty/plugin/wordpress/config.json")); - } - - return plugins.ToArray(); - } - } - - public ConsumerFactory ConsumerFactory { get; } - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - - public PluginsConfig(ConsumerFactory consumerFactory, BaseCommonLinkUtility baseCommonLinkUtility) - { - ConsumerFactory = consumerFactory; - BaseCommonLinkUtility = baseCommonLinkUtility; - } - } - - [DataContract(Name = "customization", Namespace = "")] - public class CustomizationConfig - { - public CustomizationConfig( - CoreBaseSettings coreBaseSettings, - SettingsManager settingsManager, - FileUtility fileUtility, - FilesSettingsHelper filesSettingsHelper, - AuthContext authContext, - FileSecurity fileSecurity, - IDaoFactory daoFactory, - GlobalFolderHelper globalFolderHelper, - PathProvider pathProvider, - WebImageSupplier webImageSupplier, - BaseCommonLinkUtility baseCommonLinkUtility, - CustomerConfig customerConfig, - LogoConfig logoConfig) - { - CoreBaseSettings = coreBaseSettings; - SettingsManager = settingsManager; - FileUtility = fileUtility; - FilesSettingsHelper = filesSettingsHelper; - AuthContext = authContext; - FileSecurity = fileSecurity; - DaoFactory = daoFactory; - GlobalFolderHelper = globalFolderHelper; - PathProvider = pathProvider; - WebImageSupplier = webImageSupplier; - BaseCommonLinkUtility = baseCommonLinkUtility; - Customer = customerConfig; - Logo = logoConfig; - } - - private Configuration _configuration; - - internal void SetConfiguration(Configuration configuration) - { - _configuration = configuration; - Customer.SetConfiguration(_configuration); - Logo.SetConfiguration(_configuration); - } - - public string GobackUrl; - public bool IsRetina = false; - - - [DataMember(Name = "about")] - public bool About - { - set { } - get { return !CoreBaseSettings.Standalone && !CoreBaseSettings.CustomMode; } - } - - [DataMember(Name = "customer")] - public CustomerConfig Customer; - - [DataMember(Name = "feedback", EmitDefaultValue = false)] - public FeedbackConfig Feedback - { - set { } - get - { - if (CoreBaseSettings.Standalone) return null; - if (!AdditionalWhiteLabelSettings.Instance(SettingsManager).FeedbackAndSupportEnabled) return null; - - return new FeedbackConfig - { - Url = BaseCommonLinkUtility.GetRegionalUrl( - AdditionalWhiteLabelSettings.Instance(SettingsManager).FeedbackAndSupportUrl, - CultureInfo.CurrentCulture.TwoLetterISOLanguageName), - }; - } - } - - [DataMember(Name = "forcesave", EmitDefaultValue = false)] - public bool Forcesave - { - set { } - get - { - return FileUtility.CanForcesave - && !_configuration.Document.Info.File.ProviderEntry - && ThirdPartySelector.GetAppByFileId(_configuration.Document.Info.File.ID.ToString()) == null - && FilesSettingsHelper.Forcesave; - } - } - - [DataMember(Name = "goback", EmitDefaultValue = false)] - public GobackConfig Goback - { - set { } - get - { - if (_configuration.Type == EditorType.Embedded || _configuration.Type == EditorType.External) return null; - if (!AuthContext.IsAuthenticated) return null; - if (GobackUrl != null) - { - return new GobackConfig - { - Url = GobackUrl, - }; - } - - var folderDao = DaoFactory.FolderDao; - try - { - var parent = folderDao.GetFolder(_configuration.Document.Info.File.FolderID); - var fileSecurity = FileSecurity; - if (_configuration.Document.Info.File.RootFolderType == FolderType.USER - && !Equals(_configuration.Document.Info.File.RootFolderId, GlobalFolderHelper.FolderMy) - && !fileSecurity.CanRead(parent)) - { - if (fileSecurity.CanRead(_configuration.Document.Info.File)) - { - return new GobackConfig - { - Url = PathProvider.GetFolderUrl(GlobalFolderHelper.FolderShare), - }; - } - return null; - } - - return new GobackConfig - { - Url = PathProvider.GetFolderUrl(parent), - }; - } - catch (Exception) - { - return null; - } - } - } - - [DataMember(Name = "loaderLogo", EmitDefaultValue = false)] - public string LoaderLogo - { - set { } - get - { - return CoreBaseSettings.CustomMode - ? BaseCommonLinkUtility.GetFullAbsolutePath(WebImageSupplier.GetAbsoluteWebPath("loader.svg").ToLower()) - : null; - } - } - - [DataMember(Name = "loaderName", EmitDefaultValue = false)] - public string LoaderName - { - set { } - get - { - return CoreBaseSettings.CustomMode - ? " " - : null; - } - } - - [DataMember(Name = "logo")] - public LogoConfig Logo; - - [DataMember(Name = "reviewDisplay", EmitDefaultValue = false)] - public string ReviewDisplay - { - set { } - get { return _configuration.EditorConfig.ModeWrite ? null : "markup"; } - } - - public CoreBaseSettings CoreBaseSettings { get; } - public SettingsManager SettingsManager { get; } - public FileUtility FileUtility { get; } - public FilesSettingsHelper FilesSettingsHelper { get; } - public AuthContext AuthContext { get; } - public FileSecurity FileSecurity { get; } - public IDaoFactory DaoFactory { get; } - public GlobalFolderHelper GlobalFolderHelper { get; } - public PathProvider PathProvider { get; } - public WebImageSupplier WebImageSupplier { get; } - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - - [DataContract(Name = "customer", Namespace = "")] - public class CustomerConfig - { - public CustomerConfig( - SettingsManager settingsManager, - BaseCommonLinkUtility baseCommonLinkUtility, - TenantLogoHelper tenantLogoHelper) - { - SettingsManager = settingsManager; - BaseCommonLinkUtility = baseCommonLinkUtility; - TenantLogoHelper = tenantLogoHelper; - } - - private Configuration _configuration; - - internal void SetConfiguration(Configuration configuration) - { - _configuration = configuration; - } - - [DataMember(Name = "logo")] - public string Logo - { - set { } - get { return BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.Dark, !_configuration.EditorConfig.Customization.IsRetina)); } - } - - [DataMember(Name = "name")] - public string Name - { - set { } - get - { - return (SettingsManager.Load().GetLogoText(SettingsManager) ?? "") - .Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("/", "\\/"); - } - } - - public SettingsManager SettingsManager { get; } - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - public TenantLogoHelper TenantLogoHelper { get; } - } - - [DataContract(Name = "feedback", Namespace = "")] - public class FeedbackConfig - { - [DataMember(Name = "url")] - public string Url; - - [DataMember(Name = "visible")] - public bool Visible = true; - } - - [DataContract(Name = "goback", Namespace = "")] - public class GobackConfig - { - [DataMember(Name = "url", EmitDefaultValue = false)] - public string Url; - } - - [DataContract(Name = "logo", Namespace = "")] - public class LogoConfig - { - public LogoConfig( - SettingsManager settingsManager, - BaseCommonLinkUtility baseCommonLinkUtility, - TenantLogoHelper tenantLogoHelper) - { - BaseCommonLinkUtility = baseCommonLinkUtility; - TenantLogoHelper = tenantLogoHelper; - SettingsManager = settingsManager; - } - - private Configuration _configuration; - internal void SetConfiguration(Configuration configuration) - { - _configuration = configuration; - } - - [DataMember(Name = "image")] - public string Image - { - set { } - get - { - return - _configuration.Type == EditorType.Embedded - ? null - : BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.DocsEditor, !_configuration.EditorConfig.Customization.IsRetina)); - } - } - - [DataMember(Name = "imageEmbedded", EmitDefaultValue = false)] - public string ImageEmbedded - { - set { } - get - { - return - _configuration.Type != EditorType.Embedded - ? null - : BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.Dark, !_configuration.EditorConfig.Customization.IsRetina)); - } - } - - [DataMember(Name = "url")] - public string Url - { - set { } - get { return CompanyWhiteLabelSettings.Instance(SettingsManager).Site; } - } - - public BaseCommonLinkUtility BaseCommonLinkUtility { get; } - public TenantLogoHelper TenantLogoHelper { get; } - public SettingsManager SettingsManager { get; } - } - } - - [DataContract(Name = "user", Namespace = "")] - public class UserConfig - { - [DataMember(Name = "id", EmitDefaultValue = false)] - public string Id; - - [DataMember(Name = "name", EmitDefaultValue = false)] - public string Name; - } - - #endregion } - #endregion + [DataMember(Name = "callbackUrl", EmitDefaultValue = false)] + public string CallbackUrl; + + [DataMember(Name = "createUrl", EmitDefaultValue = false)] + public string CreateUrl + { + set { } + get + { + if (_configuration.Document.Info.Type != EditorType.Desktop) return null; + if (!AuthContext.IsAuthenticated || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) return null; + + return GetCreateUrl(_configuration.GetFileType); + } + } + + [DataMember(Name = "plugins", EmitDefaultValue = false)] + public PluginsConfig Plugins; + + [DataMember(Name = "customization", EmitDefaultValue = false)] + public CustomizationConfig Customization; + + [DataMember(Name = "embedded", EmitDefaultValue = false)] + public EmbeddedConfig Embedded + { + set { _embeddedConfig = value; } + get { return _configuration.Document.Info.Type == EditorType.Embedded ? _embeddedConfig : null; } + } + + [DataMember(Name = "fileChoiceUrl", EmitDefaultValue = false)] + public string FileChoiceUrl; + + [DataMember(Name = "lang")] + public string Lang + { + set { } + get { return _userInfo.GetCulture().Name; } + } + + //todo: remove old feild after release 5.2+ + [DataMember(Name = "mergeFolderUrl", EmitDefaultValue = false)] + public string MergeFolderUrl; + + [DataMember(Name = "mode")] + public string Mode + { + set { } + get { return ModeWrite ? "edit" : "view"; } + } + + public UserManager UserManager { get; } + public AuthContext AuthContext { get; } + public FilesLinkUtility FilesLinkUtility { get; } + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + + [DataMember(Name = "saveAsUrl", EmitDefaultValue = false)] + public string SaveAsUrl; + + [DataMember(Name = "sharingSettingsUrl", EmitDefaultValue = false)] + public string SharingSettingsUrl; + + [DataMember(Name = "user")] + public UserConfig User; + + private string GetCreateUrl(FileType fileType) + { + string title; + switch (fileType) + { + case FileType.Document: + title = FilesJSResource.TitleNewFileText; + break; + case FileType.Spreadsheet: + title = FilesJSResource.TitleNewFileSpreadsheet; + break; + case FileType.Presentation: + title = FilesJSResource.TitleNewFilePresentation; + break; + default: + return null; + } + + Configuration.DocType.TryGetValue(fileType, out var documentType); + + return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath) + + "?" + FilesLinkUtility.Action + "=create" + + "&doctype=" + documentType + + "&" + FilesLinkUtility.FileTitle + "=" + HttpUtility.UrlEncode(title); + } + } + + #endregion + + [DataContract(Name = "actionLink", Namespace = "")] + public class ActionLinkConfig + { + [DataMember(Name = "action", EmitDefaultValue = false)] + public ActionConfig Action; + + + [DataContract(Name = "action", Namespace = "")] + public class ActionConfig + { + [DataMember(Name = "type", EmitDefaultValue = false)] + public string Type; + + [DataMember(Name = "data", EmitDefaultValue = false)] + public string Data; + } + + + public static string Serialize(ActionLinkConfig actionLinkConfig) + { + using (var ms = new MemoryStream()) + { + var serializer = new DataContractJsonSerializer(typeof(ActionLinkConfig)); + serializer.WriteObject(ms, actionLinkConfig); + ms.Seek(0, SeekOrigin.Begin); + return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length); + } + } + } + + [DataContract(Name = "embedded", Namespace = "")] + public class EmbeddedConfig + { + public string ShareLinkParam; + + [DataMember(Name = "embedUrl", EmitDefaultValue = false)] + public string EmbedUrl + { + set { } + get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FilesBaseAbsolutePath + FilesLinkUtility.EditorPage + "?" + FilesLinkUtility.Action + "=embedded" + ShareLinkParam); } + } + + [DataMember(Name = "saveUrl", EmitDefaultValue = false)] + public string SaveUrl + { + set { } + get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath + "?" + FilesLinkUtility.Action + "=download" + ShareLinkParam); } + } + + [DataMember(Name = "shareUrl", EmitDefaultValue = false)] + public string ShareUrl + { + set { } + get { return BaseCommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FilesBaseAbsolutePath + FilesLinkUtility.EditorPage + "?" + FilesLinkUtility.Action + "=view" + ShareLinkParam); } + } + + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + public FilesLinkUtility FilesLinkUtility { get; } + + [DataMember(Name = "toolbarDocked")] + public string ToolbarDocked = "top"; + + public EmbeddedConfig(BaseCommonLinkUtility baseCommonLinkUtility, FilesLinkUtility filesLinkUtility) + { + BaseCommonLinkUtility = baseCommonLinkUtility; + FilesLinkUtility = filesLinkUtility; + } + } + + [DataContract(Name = "plugins", Namespace = "")] + public class PluginsConfig + { + [DataMember(Name = "pluginsData", EmitDefaultValue = false)] + public string[] PluginsData + { + set { } + get + { + var plugins = new List(); + + var easyBibHelper = ConsumerFactory.Get(); + if (!string.IsNullOrEmpty(easyBibHelper.AppKey)) + { + plugins.Add(BaseCommonLinkUtility.GetFullAbsolutePath("ThirdParty/plugin/easybib/config.json")); + } + + var wordpressLoginProvider = ConsumerFactory.Get(); + if (!string.IsNullOrEmpty(wordpressLoginProvider.ClientID) && + !string.IsNullOrEmpty(wordpressLoginProvider.ClientSecret) && + !string.IsNullOrEmpty(wordpressLoginProvider.RedirectUri)) + { + plugins.Add(BaseCommonLinkUtility.GetFullAbsolutePath("ThirdParty/plugin/wordpress/config.json")); + } + + return plugins.ToArray(); + } + } + + public ConsumerFactory ConsumerFactory { get; } + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + + public PluginsConfig(ConsumerFactory consumerFactory, BaseCommonLinkUtility baseCommonLinkUtility) + { + ConsumerFactory = consumerFactory; + BaseCommonLinkUtility = baseCommonLinkUtility; + } + } + + [DataContract(Name = "customization", Namespace = "")] + public class CustomizationConfig + { + public CustomizationConfig( + CoreBaseSettings coreBaseSettings, + SettingsManager settingsManager, + FileUtility fileUtility, + FilesSettingsHelper filesSettingsHelper, + AuthContext authContext, + FileSecurity fileSecurity, + IDaoFactory daoFactory, + GlobalFolderHelper globalFolderHelper, + PathProvider pathProvider, + WebImageSupplier webImageSupplier, + BaseCommonLinkUtility baseCommonLinkUtility, + CustomerConfig customerConfig, + LogoConfig logoConfig) + { + CoreBaseSettings = coreBaseSettings; + SettingsManager = settingsManager; + FileUtility = fileUtility; + FilesSettingsHelper = filesSettingsHelper; + AuthContext = authContext; + FileSecurity = fileSecurity; + DaoFactory = daoFactory; + GlobalFolderHelper = globalFolderHelper; + PathProvider = pathProvider; + WebImageSupplier = webImageSupplier; + BaseCommonLinkUtility = baseCommonLinkUtility; + Customer = customerConfig; + Logo = logoConfig; + } + + private Configuration _configuration; + + internal void SetConfiguration(Configuration configuration) + { + _configuration = configuration; + Customer.SetConfiguration(_configuration); + Logo.SetConfiguration(_configuration); + } + + public string GobackUrl; + public bool IsRetina = false; + + + [DataMember(Name = "about")] + public bool About + { + set { } + get { return !CoreBaseSettings.Standalone && !CoreBaseSettings.CustomMode; } + } + + [DataMember(Name = "customer")] + public CustomerConfig Customer; + + [DataMember(Name = "feedback", EmitDefaultValue = false)] + public FeedbackConfig Feedback + { + set { } + get + { + if (CoreBaseSettings.Standalone) return null; + if (!AdditionalWhiteLabelSettings.Instance(SettingsManager).FeedbackAndSupportEnabled) return null; + + return new FeedbackConfig + { + Url = BaseCommonLinkUtility.GetRegionalUrl( + AdditionalWhiteLabelSettings.Instance(SettingsManager).FeedbackAndSupportUrl, + CultureInfo.CurrentCulture.TwoLetterISOLanguageName), + }; + } + } + + [DataMember(Name = "forcesave", EmitDefaultValue = false)] + public bool Forcesave + { + set { } + get + { + return FileUtility.CanForcesave + && !_configuration.Document.Info.File.ProviderEntry + && ThirdPartySelector.GetAppByFileId(_configuration.Document.Info.File.ID.ToString()) == null + && FilesSettingsHelper.Forcesave; + } + } + + [DataMember(Name = "goback", EmitDefaultValue = false)] + public GobackConfig Goback + { + set { } + get + { + if (_configuration.Type == EditorType.Embedded || _configuration.Type == EditorType.External) return null; + if (!AuthContext.IsAuthenticated) return null; + if (GobackUrl != null) + { + return new GobackConfig + { + Url = GobackUrl, + }; + } + + var folderDao = DaoFactory.GetFolderDao(); + try + { + var parent = folderDao.GetFolder(_configuration.Document.Info.File.FolderID); + var fileSecurity = FileSecurity; + if (_configuration.Document.Info.File.RootFolderType == FolderType.USER + && !Equals(_configuration.Document.Info.File.RootFolderId, GlobalFolderHelper.FolderMy) + && !fileSecurity.CanRead(parent)) + { + if (fileSecurity.CanRead(_configuration.Document.Info.File)) + { + return new GobackConfig + { + Url = PathProvider.GetFolderUrl(GlobalFolderHelper.FolderShare), + }; + } + return null; + } + + return new GobackConfig + { + Url = PathProvider.GetFolderUrl(parent), + }; + } + catch (Exception) + { + return null; + } + } + } + + [DataMember(Name = "loaderLogo", EmitDefaultValue = false)] + public string LoaderLogo + { + set { } + get + { + return CoreBaseSettings.CustomMode + ? BaseCommonLinkUtility.GetFullAbsolutePath(WebImageSupplier.GetAbsoluteWebPath("loader.svg").ToLower()) + : null; + } + } + + [DataMember(Name = "loaderName", EmitDefaultValue = false)] + public string LoaderName + { + set { } + get + { + return CoreBaseSettings.CustomMode + ? " " + : null; + } + } + + [DataMember(Name = "logo")] + public LogoConfig Logo; + + [DataMember(Name = "reviewDisplay", EmitDefaultValue = false)] + public string ReviewDisplay + { + set { } + get { return _configuration.EditorConfig.ModeWrite ? null : "markup"; } + } + + public CoreBaseSettings CoreBaseSettings { get; } + public SettingsManager SettingsManager { get; } + public FileUtility FileUtility { get; } + public FilesSettingsHelper FilesSettingsHelper { get; } + public AuthContext AuthContext { get; } + public FileSecurity FileSecurity { get; } + public IDaoFactory DaoFactory { get; } + public GlobalFolderHelper GlobalFolderHelper { get; } + public PathProvider PathProvider { get; } + public WebImageSupplier WebImageSupplier { get; } + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + } + + [DataContract(Name = "customer", Namespace = "")] + public class CustomerConfig + { + public CustomerConfig( + SettingsManager settingsManager, + BaseCommonLinkUtility baseCommonLinkUtility, + TenantLogoHelper tenantLogoHelper) + { + SettingsManager = settingsManager; + BaseCommonLinkUtility = baseCommonLinkUtility; + TenantLogoHelper = tenantLogoHelper; + } + + private Configuration _configuration; + + internal void SetConfiguration(Configuration configuration) + { + _configuration = configuration; + } + + [DataMember(Name = "logo")] + public string Logo + { + set { } + get { return BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.Dark, !_configuration.EditorConfig.Customization.IsRetina)); } + } + + [DataMember(Name = "name")] + public string Name + { + set { } + get + { + return (SettingsManager.Load().GetLogoText(SettingsManager) ?? "") + .Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("/", "\\/"); + } + } + + public SettingsManager SettingsManager { get; } + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + public TenantLogoHelper TenantLogoHelper { get; } + } + + [DataContract(Name = "feedback", Namespace = "")] + public class FeedbackConfig + { + [DataMember(Name = "url")] + public string Url; + + [DataMember(Name = "visible")] + public bool Visible = true; + } + + [DataContract(Name = "goback", Namespace = "")] + public class GobackConfig + { + [DataMember(Name = "url", EmitDefaultValue = false)] + public string Url; + } + + [DataContract(Name = "logo", Namespace = "")] + public class LogoConfig + { + public LogoConfig( + SettingsManager settingsManager, + BaseCommonLinkUtility baseCommonLinkUtility, + TenantLogoHelper tenantLogoHelper) + { + BaseCommonLinkUtility = baseCommonLinkUtility; + TenantLogoHelper = tenantLogoHelper; + SettingsManager = settingsManager; + } + + private Configuration _configuration; + internal void SetConfiguration(Configuration configuration) + { + _configuration = configuration; + } + + [DataMember(Name = "image")] + public string Image + { + set { } + get + { + return + _configuration.Type == EditorType.Embedded + ? null + : BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.DocsEditor, !_configuration.EditorConfig.Customization.IsRetina)); + } + } + + [DataMember(Name = "imageEmbedded", EmitDefaultValue = false)] + public string ImageEmbedded + { + set { } + get + { + return + _configuration.Type != EditorType.Embedded + ? null + : BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.Dark, !_configuration.EditorConfig.Customization.IsRetina)); + } + } + + [DataMember(Name = "url")] + public string Url + { + set { } + get { return CompanyWhiteLabelSettings.Instance(SettingsManager).Site; } + } + + public BaseCommonLinkUtility BaseCommonLinkUtility { get; } + public TenantLogoHelper TenantLogoHelper { get; } + public SettingsManager SettingsManager { get; } + } + + [DataContract(Name = "user", Namespace = "")] + public class UserConfig + { + [DataMember(Name = "id", EmitDefaultValue = false)] + public string Id; + + [DataMember(Name = "name", EmitDefaultValue = false)] + public string Name; } public static class ConfigurationExtention @@ -941,7 +926,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddDocumentConfigService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddDocumentServiceConnectorService() @@ -951,7 +937,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddInfoConfigService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddBreadCrumbsManagerService() @@ -960,7 +947,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddEditorConfigurationService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddUserManagerService() @@ -993,7 +981,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddCustomizationConfigService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddCoreBaseSettingsService() @@ -1013,7 +1002,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddCustomerConfigService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddSettingsManagerService() @@ -1023,7 +1013,8 @@ namespace ASC.Web.Files.Services.DocumentService public static DIHelper AddLogoConfigService(this DIHelper services) { - services.TryAddTransient(); + services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddSettingsManagerService() diff --git a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs index 84616f3b68..6e9dad448c 100644 --- a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs +++ b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs @@ -93,12 +93,12 @@ namespace ASC.Web.Files.Services.DocumentService ServiceProvider = serviceProvider; } - public File GetParams(object fileId, int version, string doc, bool editPossible, bool tryEdit, bool tryCoauth, out Configuration configuration) + public File GetParams(T fileId, int version, string doc, bool editPossible, bool tryEdit, bool tryCoauth, out Configuration configuration) { var lastVersion = true; FileShare linkRight; - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); linkRight = FileShareLink.Check(doc, fileDao, out var file); @@ -120,7 +120,7 @@ namespace ASC.Web.Files.Services.DocumentService return GetParams(file, lastVersion, linkRight, true, true, editPossible, tryEdit, tryCoauth, out configuration); } - public File GetParams(File file, bool lastVersion, FileShare linkRight, bool rightToRename, bool rightToEdit, bool editPossible, bool tryEdit, bool tryCoauth, out Configuration configuration) + public File GetParams(File file, bool lastVersion, FileShare linkRight, bool rightToRename, bool rightToEdit, bool editPossible, bool tryEdit, bool tryCoauth, out Configuration configuration) { if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); if (!string.IsNullOrEmpty(file.Error)) throw new Exception(file.Error); @@ -145,17 +145,17 @@ namespace ASC.Web.Files.Services.DocumentService var fileSecurity = FileSecurity; rightToEdit = rightToEdit && (linkRight == FileShare.ReadWrite - || fileSecurity.CanEdit(file)); + || fileSecurity.CanEdit(file)); if (editPossible && !rightToEdit) { editPossible = false; } - rightToRename = rightToRename && rightToEdit && fileSecurity.CanEdit(file); + rightToRename = rightToRename && rightToEdit && fileSecurity.CanEdit(file); rightToReview = rightToReview && (linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanReview(file)); + || fileSecurity.CanReview(file)); if (reviewPossible && !rightToReview) { reviewPossible = false; @@ -163,7 +163,7 @@ namespace ASC.Web.Files.Services.DocumentService rightToFillForms = rightToFillForms && (linkRight == FileShare.FillForms || linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanFillForms(file)); + || fileSecurity.CanFillForms(file)); if (fillFormsPossible && !rightToFillForms) { fillFormsPossible = false; @@ -171,7 +171,7 @@ namespace ASC.Web.Files.Services.DocumentService rightToComment = rightToComment && (linkRight == FileShare.Comment || linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanComment(file)); + || fileSecurity.CanComment(file)); if (commentPossible && !rightToComment) { commentPossible = false; @@ -179,7 +179,7 @@ namespace ASC.Web.Files.Services.DocumentService if (linkRight == FileShare.Restrict && !(editPossible || reviewPossible || fillFormsPossible || commentPossible) - && !fileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + && !fileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -252,14 +252,14 @@ namespace ASC.Web.Files.Services.DocumentService var fileStable = file; if (lastVersion && file.Forcesave != ForcesaveType.None && tryEdit) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); fileStable = fileDao.GetFileStable(file.ID, file.Version); } var docKey = GetDocKey(fileStable); var modeWrite = (editPossible || reviewPossible || fillFormsPossible || commentPossible) && tryEdit; - configuration = new Configuration(file, ServiceProvider) + configuration = new Configuration(file, ServiceProvider) { Document = { @@ -321,14 +321,14 @@ namespace ASC.Web.Files.Services.DocumentService } - public void CheckUsersForDrop(File file) + public void CheckUsersForDrop(File file) { var fileSecurity = FileSecurity; var sharedLink = - fileSecurity.CanEdit(file, FileConstant.ShareLinkId) - || fileSecurity.CanReview(file, FileConstant.ShareLinkId) - || fileSecurity.CanFillForms(file, FileConstant.ShareLinkId) - || fileSecurity.CanComment(file, FileConstant.ShareLinkId); + fileSecurity.CanEdit(file, FileConstant.ShareLinkId) + || fileSecurity.CanReview(file, FileConstant.ShareLinkId) + || fileSecurity.CanFillForms(file, FileConstant.ShareLinkId) + || fileSecurity.CanComment(file, FileConstant.ShareLinkId); var usersDrop = FileTracker.GetEditingBy(file.ID) .Where(uid => @@ -337,7 +337,7 @@ namespace ASC.Web.Files.Services.DocumentService { return !sharedLink; } - return !fileSecurity.CanEdit(file, uid) && !fileSecurity.CanReview(file, uid) && !fileSecurity.CanFillForms(file, uid) && !fileSecurity.CanComment(file, uid); + return !fileSecurity.CanEdit(file, uid) && !fileSecurity.CanReview(file, uid) && !fileSecurity.CanFillForms(file, uid) && !fileSecurity.CanComment(file, uid); }) .Select(u => u.ToString()).ToArray(); @@ -346,7 +346,7 @@ namespace ASC.Web.Files.Services.DocumentService var fileStable = file; if (file.Forcesave != ForcesaveType.None) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); fileStable = fileDao.GetFileStable(file.ID, file.Version); } @@ -359,7 +359,7 @@ namespace ASC.Web.Files.Services.DocumentService return DocumentServiceConnector.Command(Web.Core.Files.DocumentService.CommandMethod.Drop, docKeyForTrack, fileId, null, users); } - public bool RenameFile(File file, IFileDao fileDao) + public bool RenameFile(File file, IFileDao fileDao) { if (!FileUtility.CanWebView(file.Title) && !FileUtility.CanWebEdit(file.Title) diff --git a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs index afe143ba01..69f23ea766 100644 --- a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs +++ b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs @@ -279,9 +279,9 @@ namespace ASC.Web.Files.Services.DocumentService return null; } - private void ProcessEdit(string fileId, TrackerData fileData) + private void ProcessEdit(T fileId, TrackerData fileData) { - if (ThirdPartySelector.GetAppByFileId(fileId) != null) + if (ThirdPartySelector.GetAppByFileId(fileId.ToString()) != null) { return; } @@ -290,11 +290,11 @@ namespace ASC.Web.Files.Services.DocumentService var usersDrop = new List(); string docKey; - var app = ThirdPartySelector.GetAppByFileId(fileId); + var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { File fileStable; - fileStable = DaoFactory.FileDao.GetFileStable(fileId); + fileStable = DaoFactory.GetFileDao().GetFileStable(fileId); docKey = DocumentServiceHelper.GetDocKey(fileStable); } @@ -347,7 +347,7 @@ namespace ASC.Web.Files.Services.DocumentService SocketManager.FilesChangeEditors(fileId); } - private TrackResponse ProcessSave(string fileId, TrackerData fileData) + private TrackResponse ProcessSave(T fileId, TrackerData fileData) { var comments = new List(); if (fileData.Status == TrackerStatus.Corrupted @@ -361,11 +361,11 @@ namespace ASC.Web.Files.Services.DocumentService userId = FileTracker.GetEditingBy(fileId).FirstOrDefault(); } - var app = ThirdPartySelector.GetAppByFileId(fileId); + var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { File fileStable; - fileStable = DaoFactory.FileDao.GetFileStable(fileId); + fileStable = DaoFactory.GetFileDao().GetFileStable(fileId); var docKey = DocumentServiceHelper.GetDocKey(fileStable); if (!fileData.Key.Equals(docKey)) @@ -602,7 +602,7 @@ namespace ASC.Web.Files.Services.DocumentService } - private void StoringFileAfterError(string fileId, string userId, string downloadUri) + private void StoringFileAfterError(T fileId, string userId, string downloadUri) { try { diff --git a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs index a352d200d2..2ec9a690ff 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs @@ -45,7 +45,7 @@ namespace ASC.Web.Files.Services.WCFService { serializers[typeof(File)] = new DataContractSerializer(typeof(File)); serializers[typeof(ItemList)] = new DataContractSerializer(typeof(ItemList)); - serializers[typeof(DataWrapper)] = new DataContractSerializer(typeof(DataWrapper)); + serializers[typeof(DataWrapper<>)] = new DataContractSerializer(typeof(DataWrapper<>)); //if (WorkContext.IsMono && !string.IsNullOrEmpty(WorkContext.MonoVersion)) //{ diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index 3c4cfe1541..da12ecde02 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -118,7 +118,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder; } - else if (!_ignoreException && !FilesSecurity.CanDelete(folder)) + else if (!_ignoreException && !FilesSecurity.CanDelete(folder)) { canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId; @@ -236,7 +236,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations error = null; foreach (var file in files) { - if (!FilesSecurity.CanDelete(file)) + if (!FilesSecurity.CanDelete(file)) { error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFile; return true; diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs index 3bf68ea864..15a82bd0b6 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs @@ -168,7 +168,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations CancellationToken.ThrowIfCancellationRequested(); var folder = FolderDao.GetFolder(folderId); - if (folder == null || !FilesSecurity.CanRead(folder)) continue; + if (folder == null || !FilesSecurity.CanRead(folder)) continue; var folderPath = path + folder.Title + "/"; var files = FileDao.GetFiles(folder.ID, null, FilterType.None, false, Guid.Empty, string.Empty, true); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index 8d54bc20d3..8c1bdd87f7 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -91,7 +91,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations //TODO: check on each iteration? var toFolder = FolderDao.GetFolder(_toFolderId); if (toFolder == null) return; - if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); + if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID))) { @@ -111,7 +111,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations MoveOrCopyFolders(scope, Folders, toFolder, _copy); MoveOrCopyFiles(scope, Files, toFolder, _copy); - _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); + _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); } private void MoveOrCopyFolders(IServiceScope scope, List folderIds, Folder toFolder, bool copy) @@ -132,7 +132,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_FolderNotFound; } - else if (!FilesSecurity.CanRead(folder)) + else if (!FilesSecurity.CanRead(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFolder; } @@ -174,7 +174,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (!copy) { - if (!FilesSecurity.CanDelete(folder)) + if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -207,7 +207,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Status += string.Format("folder_{0}{1}", newFolderId, FileOperation.SPLIT_CHAR); } } - else if (!FilesSecurity.CanDelete(folder)) + else if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -236,7 +236,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } else { - if (!FilesSecurity.CanDelete(folder)) + if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -293,7 +293,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_FileNotFound; } - else if (!FilesSecurity.CanRead(file)) + else if (!FilesSecurity.CanRead(file)) { Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFile; } @@ -369,7 +369,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { if (_resolveType == FileConflictResolveType.Overwrite) { - if (!FilesSecurity.CanEdit(conflict)) + if (!FilesSecurity.CanEdit(conflict)) { Error = FilesCommonResource.ErrorMassage_SecurityException; } @@ -460,7 +460,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations error = null; foreach (var file in files) { - if (!FilesSecurity.CanDelete(file)) + if (!FilesSecurity.CanDelete(file)) { error = FilesCommonResource.ErrorMassage_SecurityException_MoveFile; return true; diff --git a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs index fe29ea8805..a363764c40 100644 --- a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs +++ b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs @@ -51,7 +51,7 @@ namespace ASC.Web.Files.Services.WCFService Folder FolderRename(string folderId, string title); - DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); + DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); object GetFolderItemsXml(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); diff --git a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs index ef1af79654..df012b7c9e 100644 --- a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs +++ b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs @@ -26,12 +26,13 @@ using System.Collections.Generic; using System.Runtime.Serialization; + using ASC.Files.Core; namespace ASC.Web.Files.Services.WCFService { [DataContract(Name = "composite_data", Namespace = "")] - public class DataWrapper + public class DataWrapper { [DataMember(IsRequired = false, Name = "entries", EmitDefaultValue = false)] public ItemList Entries { get; set; } @@ -40,10 +41,10 @@ namespace ASC.Web.Files.Services.WCFService public int Total { get; set; } [DataMember(IsRequired = false, Name = "path_parts")] - public ItemList FolderPathParts { get; set; } + public ItemList FolderPathParts { get; set; } [DataMember(IsRequired = false, Name = "folder_info")] - public Folder FolderInfo { get; set; } + public Folder FolderInfo { get; set; } [DataMember(IsRequired = false, Name = "root_folders_id_marked_as_new")] public Dictionary RootFoldersIdMarkedAsNew { get; set; } diff --git a/products/ASC.Files/Server/Services/WCFService/Wrappers/MentionWrapper.cs b/products/ASC.Files/Server/Services/WCFService/Wrappers/MentionWrapper.cs index 3eeacf3d29..4d8ecb3936 100644 --- a/products/ASC.Files/Server/Services/WCFService/Wrappers/MentionWrapper.cs +++ b/products/ASC.Files/Server/Services/WCFService/Wrappers/MentionWrapper.cs @@ -29,6 +29,7 @@ using System.Runtime.Serialization; using ASC.Core.Users; using ASC.Web.Core.Users; +using ASC.Web.Files.Services.DocumentService; namespace ASC.Web.Files.Services.WCFService { @@ -75,7 +76,7 @@ namespace ASC.Web.Files.Services.WCFService public class MentionMessageWrapper { [DataMember(Name = "actionLink")] - public DocumentService.Configuration.EditorConfiguration.ActionLinkConfig ActionLink { get; set; } + public ActionLinkConfig ActionLink { get; set; } [DataMember(Name = "emails")] public List Emails { get; set; } diff --git a/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs b/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs index 42ff57b05b..87aa69dfcd 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs @@ -46,6 +46,7 @@ using ASC.Core.Users; using ASC.FederatedLogin; using ASC.FederatedLogin.Helpers; using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; using ASC.Files.Resources; using ASC.MessagingSystem; using ASC.Security.Cryptography; @@ -66,7 +67,6 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using File = ASC.Files.Core.File; using SecurityContext = ASC.Core.SecurityContext; namespace ASC.Web.Files.ThirdPartyApp @@ -193,21 +193,21 @@ namespace ASC.Web.Files.ThirdPartyApp return AccessTokenUrl; } - public File GetFile(string fileId, out bool editable) + public File GetFile(string fileId, out bool editable) { Logger.Debug("BoxApp: get file " + fileId); - fileId = ThirdPartySelector.GetFileId(fileId); + fileId = ThirdPartySelector.GetFileId(fileId.ToString()); var token = TokenHelper.GetToken(AppAttr); - var boxFile = GetBoxFile(fileId, token); + var boxFile = GetBoxFile(fileId.ToString(), token); editable = true; if (boxFile == null) return null; var jsonFile = JObject.Parse(boxFile); - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.ID = ThirdPartySelector.BuildAppFileId(AppAttr, jsonFile.Value("id")); file.Title = Global.ReplaceInvalidCharsAndTruncate(jsonFile.Value("name")); file.CreateOn = TenantUtil.DateTimeFromUtc(jsonFile.Value("created_at")); @@ -244,11 +244,11 @@ namespace ASC.Web.Files.ThirdPartyApp return file; } - public string GetFileStreamUrl(File file) + public string GetFileStreamUrl(File file) { if (file == null) return string.Empty; - var fileId = ThirdPartySelector.GetFileId(file.ID.ToString()); + var fileId = ThirdPartySelector.GetFileId(file.ID); Logger.Debug("BoxApp: get file stream url " + fileId); @@ -273,11 +273,11 @@ namespace ASC.Web.Files.ThirdPartyApp (stream == null ? " from - " + downloadUrl : " from stream")); - fileId = ThirdPartySelector.GetFileId(fileId); + fileId = ThirdPartySelector.GetFileId(fileId.ToString()); var token = TokenHelper.GetToken(AppAttr); - var boxFile = GetBoxFile(fileId, token); + var boxFile = GetBoxFile(fileId.ToString(), token); if (boxFile == null) { Logger.Error("BoxApp: file is null"); diff --git a/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs b/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs index 0bd0ff9668..a7edb6420b 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs @@ -68,7 +68,6 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using File = ASC.Files.Core.File; using MimeMapping = ASC.Common.Web.MimeMapping; using SecurityContext = ASC.Core.SecurityContext; @@ -215,7 +214,7 @@ namespace ASC.Web.Files.ThirdPartyApp return AccessTokenUrl; } - public File GetFile(string fileId, out bool editable) + public File GetFile(string fileId, out bool editable) { Logger.Debug("GoogleDriveApp: get file " + fileId); fileId = ThirdPartySelector.GetFileId(fileId); @@ -228,7 +227,7 @@ namespace ASC.Web.Files.ThirdPartyApp var jsonFile = JObject.Parse(driveFile); - var file = ServiceProvider.GetService(); + var file = ServiceProvider.GetService>(); file.ID = ThirdPartySelector.BuildAppFileId(AppAttr, jsonFile.Value("id")); file.Title = Global.ReplaceInvalidCharsAndTruncate(GetCorrectTitle(jsonFile)); file.CreateOn = TenantUtil.DateTimeFromUtc(jsonFile.Value("createdTime")); @@ -247,7 +246,7 @@ namespace ASC.Web.Files.ThirdPartyApp return file; } - public string GetFileStreamUrl(File file) + public string GetFileStreamUrl(File file) { if (file == null) return string.Empty; diff --git a/products/ASC.Files/Server/ThirdPartyApp/IThirdPartyApp.cs b/products/ASC.Files/Server/ThirdPartyApp/IThirdPartyApp.cs index d49b5662dd..695c63cb8d 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/IThirdPartyApp.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/IThirdPartyApp.cs @@ -27,9 +27,9 @@ using System.IO; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; +using ASC.Files.Core; -using File = ASC.Files.Core.File; +using Microsoft.AspNetCore.Http; namespace ASC.Web.Files.ThirdPartyApp { @@ -39,9 +39,9 @@ namespace ASC.Web.Files.ThirdPartyApp string GetRefreshUrl(); - File GetFile(string fileId, out bool editable); + File GetFile(string fileId, out bool editable); - string GetFileStreamUrl(File file); + string GetFileStreamUrl(File file); void SaveFile(string fileId, string fileType, string downloadUrl, Stream stream); } diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index dfa84b57df..1d1000b270 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -111,20 +111,20 @@ namespace ASC.Web.Files.Utils AuthContext = authContext; } - public List GetBreadCrumbs(object folderId) + public List> GetBreadCrumbs(T folderId) { - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); return GetBreadCrumbs(folderId, folderDao); } - public List GetBreadCrumbs(object folderId, IFolderDao folderDao) + public List> GetBreadCrumbs(T folderId, IFolderDao folderDao) { - if (folderId == null) return new List(); + if (folderId == null) return new List>(); var breadCrumbs = FileSecurity.FilterRead(folderDao.GetParentFolders(folderId)).ToList(); var firstVisible = breadCrumbs.ElementAtOrDefault(0); - object rootId = null; + var rootId = 0; if (firstVisible == null) { rootId = GlobalFolderHelper.FolderShare; @@ -160,9 +160,9 @@ namespace ASC.Web.Files.Utils } } - if (rootId != null) + if (rootId != 0) { - breadCrumbs.Insert(0, folderDao.GetFolder(rootId)); + breadCrumbs.Insert(0, folderDao.GetFolder((T)Convert.ChangeType(rootId, typeof(T)))); } return breadCrumbs; @@ -243,7 +243,7 @@ namespace ASC.Web.Files.Utils cache = AscCache.Memory; } - public IEnumerable GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) + public IEnumerable GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) { total = 0; @@ -268,7 +268,7 @@ namespace ASC.Web.Files.Utils var projectLastModified = responseApi["response"].Value(); const string projectLastModifiedCacheKey = "documents/projectFolders/projectLastModified"; var projectListCacheKey = string.Format("documents/projectFolders/{0}", AuthContext.CurrentAccount.ID); - Dictionary> folderIDProjectTitle = null; + Dictionary> folderIDProjectTitle = null; if (folderIDProjectTitle == null) { @@ -280,7 +280,7 @@ namespace ASC.Web.Files.Utils if (!(responseData is JArray)) return entries.ToList(); - folderIDProjectTitle = new Dictionary>(); + folderIDProjectTitle = new Dictionary>(); foreach (JObject projectInfo in responseData.Children()) { var projectID = projectInfo["id"].Value(); @@ -302,7 +302,7 @@ namespace ASC.Web.Files.Utils if (projectInfo.TryGetValue("projectFolder", out var projectFolderIDjToken)) projectFolderID = projectFolderIDjToken.Value(); else - projectFolderID = (int)FilesIntegration.RegisterBunch("projects", "project", projectID.ToString()); + projectFolderID = FilesIntegration.RegisterBunch("projects", "project", projectID.ToString()); if (!folderIDProjectTitle.ContainsKey(projectFolderID)) folderIDProjectTitle.Add(projectFolderID, new KeyValuePair(projectID, projectTitle)); @@ -315,7 +315,7 @@ namespace ASC.Web.Files.Utils var rootKeys = folderIDProjectTitle.Keys.ToArray(); if (filter == FilterType.None || filter == FilterType.FoldersOnly) { - var folders = DaoFactory.FolderDao.GetFolders(rootKeys, filter, subjectGroup, subjectId, searchText, withSubfolders, false); + var folders = DaoFactory.GetFolderDao().GetFolders(rootKeys, filter, subjectGroup, subjectId, searchText, withSubfolders, false); var emptyFilter = string.IsNullOrEmpty(searchText) && filter == FilterType.None && subjectId == Guid.Empty; if (!emptyFilter) @@ -328,7 +328,7 @@ namespace ASC.Web.Files.Utils folders.RemoveAll(folder => rootKeys.Contains(folder.ID)); - var projectFolders = DaoFactory.FolderDao.GetFolders(projectFolderIds.ToArray(), filter, subjectGroup, subjectId, null, false, false); + var projectFolders = DaoFactory.GetFolderDao().GetFolders(projectFolderIds.ToArray(), filter, subjectGroup, subjectId, null, false, false); folders.AddRange(projectFolders); } @@ -348,7 +348,7 @@ namespace ASC.Web.Files.Utils if (filter != FilterType.FoldersOnly && withSubfolders) { - var files = DaoFactory.FileDao.GetFiles(rootKeys, filter, subjectGroup, subjectId, searchText, searchInContent).ToList(); + var files = DaoFactory.GetFileDao().GetFiles(rootKeys, filter, subjectGroup, subjectId, searchText, searchInContent).ToList(); files = fileSecurity.FilterRead(files).ToList(); entries = entries.Concat(files); } @@ -360,7 +360,7 @@ namespace ASC.Web.Files.Utils else if (parent.FolderType == FolderType.SHARE) { //share - var shared = (IEnumerable)fileSecurity.GetSharesForMe(filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders); + var shared = (IEnumerable)fileSecurity.GetSharesForMe(filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders); entries = entries.Concat(shared); @@ -372,12 +372,12 @@ namespace ASC.Web.Files.Utils if (parent.FolderType == FolderType.TRASH) withSubfolders = false; - var folders = DaoFactory.FolderDao.GetFolders(parent.ID, orderBy, filter, subjectGroup, subjectId, searchText, withSubfolders).Cast(); - folders = fileSecurity.FilterRead(folders); + var folders = DaoFactory.GetFolderDao().GetFolders(parent.ID, orderBy, filter, subjectGroup, subjectId, searchText, withSubfolders); + folders = fileSecurity.FilterRead(folders).ToList(); entries = entries.Concat(folders); - var files = DaoFactory.FileDao.GetFiles(parent.ID, orderBy, filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders).Cast(); - files = fileSecurity.FilterRead(files); + var files = DaoFactory.GetFileDao().GetFiles(parent.ID, orderBy, filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders); + files = fileSecurity.FilterRead(files).ToList(); entries = entries.Concat(files); if (filter == FilterType.None || filter == FilterType.FoldersOnly) @@ -415,9 +415,9 @@ namespace ASC.Web.Files.Utils return entries; } - public IEnumerable GetThirpartyFolders(Folder parent, string searchText = null) + public IEnumerable> GetThirpartyFolders(Folder parent, string searchText = null) { - var folderList = new List(); + var folderList = new List>(); if ((parent.ID.Equals(GlobalFolderHelper.FolderMy) || parent.ID.Equals(GlobalFolderHelper.FolderCommon)) && ThirdpartyConfiguration.SupportInclusion @@ -432,8 +432,8 @@ namespace ASC.Web.Files.Utils var providers = providerDao.GetProvidersInfo(parent.RootFolderType, searchText); folderList = providers - .Select(providerInfo => GetFakeThirdpartyFolder(providerInfo, parent.ID)) - .Where(fileSecurity.CanRead).ToList(); + .Select(providerInfo => GetFakeThirdpartyFolder(providerInfo, parent.ID)) + .Where(r => fileSecurity.CanRead(r)).ToList(); if (folderList.Any()) { @@ -585,14 +585,14 @@ namespace ASC.Web.Files.Utils return result; } - public Folder GetFakeThirdpartyFolder(IProviderInfo providerInfo, object parentFolderId = null) + public Folder GetFakeThirdpartyFolder(IProviderInfo providerInfo, object parentFolderId = null) { //Fake folder. Don't send request to third party - var folder = ServiceProvider.GetService(); + var folder = ServiceProvider.GetService>(); - folder.ParentFolderID = parentFolderId; + folder.ParentFolderID = (T)parentFolderId; - folder.ID = providerInfo.RootFolderId; + folder.ID = (T)providerInfo.RootFolderId; folder.CreateBy = providerInfo.Owner; folder.CreateOn = providerInfo.CreateOn; folder.FolderType = FolderType.DEFAULT; @@ -612,12 +612,12 @@ namespace ASC.Web.Files.Utils } - public List GetBreadCrumbs(object folderId) + public List> GetBreadCrumbs(T folderId) { return BreadCrumbsManager.GetBreadCrumbs(folderId); } - public List GetBreadCrumbs(object folderId, IFolderDao folderDao) + public List> GetBreadCrumbs(T folderId, IFolderDao folderDao) { return BreadCrumbsManager.GetBreadCrumbs(folderId, folderDao); } @@ -665,146 +665,6 @@ namespace ASC.Web.Files.Utils } - public File SaveEditing(string fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null) - { - var newExtension = string.IsNullOrEmpty(fileExtension) - ? FileUtility.GetFileExtension(downloadUri) - : fileExtension; - - var app = ThirdPartySelector.GetAppByFileId(fileId); - if (app != null) - { - app.SaveFile(fileId, newExtension, downloadUri, stream); - return null; - } - - var fileDao = DaoFactory.FileDao; - var editLink = FileShareLink.Check(doc, false, fileDao, out var file); - if (file == null) - { - file = fileDao.GetFile(fileId); - } - - if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - var fileSecurity = FileSecurity; - if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); - if (checkRight && FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); - if (checkRight && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); - if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); - - var currentExt = file.ConvertedExtension; - if (string.IsNullOrEmpty(newExtension)) newExtension = FileUtility.GetInternalExtension(file.Title); - - var replaceVersion = false; - if (file.Forcesave != ForcesaveType.None) - { - if (file.Forcesave == ForcesaveType.User && FilesSettingsHelper.StoreForcesave) - { - file.Version++; - } - else - { - replaceVersion = true; - } - } - else - { - if (file.Version != 1) - { - file.VersionGroup++; - } - else - { - var storeTemplate = GlobalStore.GetStoreTemplate(); - - var path = FileConstant.NewDocPath + Thread.CurrentThread.CurrentCulture + "/"; - if (!storeTemplate.IsDirectory(path)) - { - path = FileConstant.NewDocPath + "default/"; - } - path += "new" + FileUtility.GetInternalExtension(file.Title); - - //todo: think about the criteria for saving after creation - if (file.ContentLength != storeTemplate.GetFileSize("", path)) - { - file.VersionGroup++; - } - } - file.Version++; - } - file.Forcesave = forcesave ?? ForcesaveType.None; - - if (string.IsNullOrEmpty(comment)) - comment = FilesCommonResource.CommentEdit; - - file.Encrypted = encrypted; - - file.ConvertedType = FileUtility.GetFileExtension(file.Title) != newExtension ? newExtension : null; - - if (file.ProviderEntry && !newExtension.Equals(currentExt)) - { - if (FileUtility.ExtsConvertible.Keys.Contains(newExtension) - && FileUtility.ExtsConvertible[newExtension].Contains(currentExt)) - { - if (stream != null) - { - downloadUri = PathProvider.GetTempUrl(stream, newExtension); - downloadUri = DocumentServiceConnector.ReplaceCommunityAdress(downloadUri); - } - - var key = DocumentServiceConnector.GenerateRevisionId(downloadUri); - DocumentServiceConnector.GetConvertedUri(downloadUri, newExtension, currentExt, key, null, false, out downloadUri); - - stream = null; - } - else - { - file.ID = null; - file.Title = FileUtility.ReplaceFileExtension(file.Title, newExtension); - } - - file.ConvertedType = null; - } - - using (var tmpStream = new MemoryStream()) - { - if (stream != null) - { - stream.CopyTo(tmpStream); - } - else - { - // hack. http://ubuntuforums.org/showthread.php?t=1841740 - if (WorkContext.IsMono) - { - ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; - } - - var req = (HttpWebRequest)WebRequest.Create(downloadUri); - using (var editedFileStream = new ResponseStream(req.GetResponse())) - { - editedFileStream.CopyTo(tmpStream); - } - } - tmpStream.Position = 0; - - file.ContentLength = tmpStream.Length; - file.Comment = string.IsNullOrEmpty(comment) ? null : comment; - if (replaceVersion) - { - file = fileDao.ReplaceFileVersion(file, tmpStream); - } - else - { - file = fileDao.SaveFile(file, tmpStream); - } - } - - FileMarker.MarkAsNew(file); - FileMarker.RemoveMarkAsNew(file); - return file; - } - public File SaveEditing(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null) { var newExtension = string.IsNullOrEmpty(fileExtension) @@ -819,7 +679,7 @@ namespace ASC.Web.Files.Utils } var fileDao = DaoFactory.GetFileDao(); - var editLink = FileShareLink.Check(doc, false, fileDao, out var file); + var editLink = FileShareLink.Check(doc, false, fileDao, out var file); if (file == null) { file = fileDao.GetFile(fileId); @@ -827,7 +687,7 @@ namespace ASC.Web.Files.Utils if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (checkRight && FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (checkRight && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -940,12 +800,12 @@ namespace ASC.Web.Files.Utils } } - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); FileMarker.RemoveMarkAsNew(file); return file; } - public void TrackEditing(string fileId, Guid tabId, Guid userId, string doc, bool editingAlone = false) + public void TrackEditing(T fileId, Guid tabId, Guid userId, string doc, bool editingAlone = false) { bool checkRight; if (FileTracker.GetEditingBy(fileId).Contains(userId)) @@ -955,14 +815,14 @@ namespace ASC.Web.Files.Utils } bool editLink; - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); editLink = FileShareLink.Check(doc, false, fileDao, out var file); if (file == null) file = fileDao.GetFile(fileId); if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - if (!editLink && (!fileSecurity.CanEdit(file, userId) && !fileSecurity.CanReview(file, userId) && !fileSecurity.CanFillForms(file, userId) && !fileSecurity.CanComment(file, userId) || UserManager.GetUsers(userId).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (!editLink && (!fileSecurity.CanEdit(file, userId) && !fileSecurity.CanReview(file, userId) && !fileSecurity.CanFillForms(file, userId) && !fileSecurity.CanComment(file, userId) || UserManager.GetUsers(userId).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(file.ID, userId)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -973,81 +833,6 @@ namespace ASC.Web.Files.Utils } } - - public File UpdateToVersionFile(object fileId, int version, string doc = null, bool checkRight = true) - { - var fileDao = DaoFactory.FileDao; - if (version < 1) throw new ArgumentNullException("version"); - - var editLink = FileShareLink.Check(doc, false, fileDao, out var fromFile); - - if (fromFile == null) - fromFile = fileDao.GetFile(fileId); - - if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - - if (fromFile.Version != version) - fromFile = fileDao.GetFile(fromFile.ID, Math.Min(fromFile.Version, version)); - - if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); - if (FileLockedForMe(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); - if (checkRight && FileTracker.IsEditing(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); - if (fromFile.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); - if (fromFile.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); - - var exists = cache.Get(UPDATE_LIST + fileId.ToString()) != null; - if (exists) - { - throw new Exception(FilesCommonResource.ErrorMassage_UpdateEditingFile); - } - else - { - cache.Insert(UPDATE_LIST + fileId.ToString(), fileId.ToString(), TimeSpan.FromMinutes(2)); - } - - try - { - var currFile = fileDao.GetFile(fileId); - var newFile = ServiceProvider.GetService(); - - newFile.ID = fromFile.ID; - newFile.Version = currFile.Version + 1; - newFile.VersionGroup = currFile.VersionGroup; - newFile.Title = FileUtility.ReplaceFileExtension(currFile.Title, FileUtility.GetFileExtension(fromFile.Title)); - newFile.FileStatus = currFile.FileStatus; - newFile.FolderID = currFile.FolderID; - newFile.CreateBy = currFile.CreateBy; - newFile.CreateOn = currFile.CreateOn; - newFile.ModifiedBy = fromFile.ModifiedBy; - newFile.ModifiedOn = fromFile.ModifiedOn; - newFile.ConvertedType = fromFile.ConvertedType; - newFile.Comment = string.Format(FilesCommonResource.CommentRevert, fromFile.ModifiedOnString); - newFile.Encrypted = fromFile.Encrypted; - - using (var stream = fileDao.GetFileStream(fromFile)) - { - newFile.ContentLength = stream.CanSeek ? stream.Length : fromFile.ContentLength; - newFile = fileDao.SaveFile(newFile, stream); - } - - FileMarker.MarkAsNew(newFile); - - SetFileStatus(newFile); - - return newFile; - } - catch (Exception e) - { - Logger.Error(string.Format("Error on update {0} to version {1}", fileId, version), e); - throw new Exception(e.Message, e); - } - finally - { - cache.Remove(UPDATE_LIST + fromFile.ID); - } - } - public File UpdateToVersionFile(T fileId, int version, string doc = null, bool checkRight = true) { var fileDao = DaoFactory.GetFileDao(); @@ -1064,7 +849,7 @@ namespace ASC.Web.Files.Utils fromFile = fileDao.GetFile(fromFile.ID, Math.Min(fromFile.Version, version)); if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (checkRight && FileTracker.IsEditing(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); if (fromFile.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -1105,7 +890,7 @@ namespace ASC.Web.Files.Utils newFile = fileDao.SaveFile(newFile, stream); } - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); SetFileStatus(newFile); @@ -1122,47 +907,6 @@ namespace ASC.Web.Files.Utils } } - public File CompleteVersionFile(object fileId, int version, bool continueVersion, bool checkRight = true) - { - var fileDao = DaoFactory.FileDao; - var fileVersion = version > 0 -? fileDao.GetFile(fileId, version) -: fileDao.GetFile(fileId); - if (fileVersion == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); - if (FileLockedForMe(fileVersion.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); - if (fileVersion.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); - if (fileVersion.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); - - var lastVersionFile = fileDao.GetFile(fileVersion.ID); - - if (continueVersion) - { - if (lastVersionFile.VersionGroup > 1) - { - fileDao.ContinueVersion(fileVersion.ID, fileVersion.Version); - lastVersionFile.VersionGroup--; - } - } - else - { - if (!FileTracker.IsEditing(lastVersionFile.ID)) - { - if (fileVersion.Version == lastVersionFile.Version) - { - lastVersionFile = UpdateToVersionFile(fileVersion.ID, fileVersion.Version, null, checkRight); - } - - fileDao.CompleteVersion(fileVersion.ID, fileVersion.Version); - lastVersionFile.VersionGroup++; - } - } - - SetFileStatus(lastVersionFile); - - return lastVersionFile; - } - public File CompleteVersionFile(T fileId, int version, bool continueVersion, bool checkRight = true) { var fileDao = DaoFactory.GetFileDao(); @@ -1170,7 +914,7 @@ namespace ASC.Web.Files.Utils ? fileDao.GetFile(fileId, version) : fileDao.GetFile(fileId); if (fileVersion == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(fileVersion.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (fileVersion.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); if (fileVersion.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); @@ -1204,13 +948,13 @@ namespace ASC.Web.Files.Utils return lastVersionFile; } - public bool FileRename(object fileId, string title, out File file) + public bool FileRename(T fileId, string title, out File file) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); file = fileDao.GetFile(fileId); if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (!FileSecurity.CanEdit(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); - if (!FileSecurity.CanDelete(file) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); + if (!FileSecurity.CanEdit(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); + if (!FileSecurity.CanDelete(file) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); if (FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (file.ProviderEntry && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_UpdateEditingFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -1245,7 +989,8 @@ namespace ASC.Web.Files.Utils //Long operation - public void DeleteSubitems(object parentId, IFolderDao folderDao, IFileDao fileDao) + + public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao fileDao) { var folders = folderDao.GetFolders(parentId); foreach (var folder in folders) @@ -1264,58 +1009,6 @@ namespace ASC.Web.Files.Utils } } - public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao fileDao) - { - var folders = folderDao.GetFolders(parentId); - foreach (var folder in folders) - { - DeleteSubitems(folder.ID, folderDao, fileDao); - - Logger.InfoFormat("Delete folder {0} in {1}", folder.ID, parentId); - folderDao.DeleteFolder(folder.ID); - } - - var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true); - foreach (var file in files) - { - Logger.InfoFormat("Delete file {0} in {1}", file.ID, parentId); - fileDao.DeleteFile(file.ID); - } - } - public void MoveSharedItems(object parentId, object toId, IFolderDao folderDao, IFileDao fileDao) - { - var fileSecurity = FileSecurity; - - var folders = folderDao.GetFolders(parentId); - foreach (var folder in folders) - { - var shared = folder.Shared - && fileSecurity.GetShares(folder).Any(record => record.Share != FileShare.Restrict); - if (shared) - { - Logger.InfoFormat("Move shared folder {0} from {1} to {2}", folder.ID, parentId, toId); - folderDao.MoveFolder(folder.ID, toId, null); - } - else - { - MoveSharedItems(folder.ID, toId, folderDao, fileDao); - } - } - - var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true); - foreach (var file - in files.Where(file => - file.Shared - && fileSecurity.GetShares(file) - .Any(record => - record.Subject != FileConstant.ShareLinkId - && record.Share != FileShare.Restrict))) - { - Logger.InfoFormat("Move shared file {0} from {1} to {2}", file.ID, parentId, toId); - fileDao.MoveFile(file.ID, toId); - } - } - public void MoveSharedItems(T parentId, T toId, IFolderDao folderDao, IFileDao fileDao) { var fileSecurity = FileSecurity; diff --git a/products/ASC.Files/Server/Utils/FileConverter.cs b/products/ASC.Files/Server/Utils/FileConverter.cs index 7d9160b73f..17b843e9b1 100644 --- a/products/ASC.Files/Server/Utils/FileConverter.cs +++ b/products/ASC.Files/Server/Utils/FileConverter.cs @@ -230,11 +230,11 @@ namespace ASC.Web.Files.Utils return new ResponseStream(((HttpWebRequest)WebRequest.Create(convertUri)).GetResponse()); } - public File ExecSync(File file, string doc) + public File ExecSync(File file, string doc) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var fileSecurity = FileSecurity; - if (!fileSecurity.CanRead(file)) + if (!fileSecurity.CanRead(file)) { var readLink = FileShareLink.Check(doc, true, fileDao, out file); if (file == null) @@ -258,7 +258,7 @@ namespace ASC.Web.Files.Utils return SaveConvertedFile(file, convertUri); } - public void ExecAsync(File file, bool deleteAfter, string password = null) + public void ExecAsync(File file, bool deleteAfter, string password = null) { if (!MustConvert(file)) { @@ -299,7 +299,7 @@ namespace ASC.Web.Files.Utils if (timer == null) { - timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); + timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); } else { @@ -327,7 +327,7 @@ namespace ASC.Web.Files.Utils var file = pair.Key; var key = GetKey(file); var operation = cache.Get(key); - if (operation != null && (pair.Value || fileSecurity.CanRead(file))) + if (operation != null && (pair.Value || fileSecurity.CanRead(file))) { result.Add(operation); lock (locker) @@ -363,7 +363,7 @@ namespace ASC.Web.Files.Utils File.Serialize(file).Replace('"', '\'')); } - private void CheckConvertFilesStatus(object _) + private void CheckConvertFilesStatus(object _) { if (Monitor.TryEnter(singleThread)) { @@ -376,7 +376,7 @@ namespace ASC.Web.Files.Utils try { - List filesIsConverting; + List> filesIsConverting = new List>(); lock (locker) { timer.Change(Timeout.Infinite, Timeout.Infinite); @@ -398,10 +398,11 @@ namespace ASC.Web.Files.Utils return; } - filesIsConverting = conversionQueue - .Where(x => string.IsNullOrEmpty(x.Value.Processed)) - .Select(x => x.Key) - .ToList(); + //TODO: + //filesIsConverting = conversionQueue + // .Where(x => string.IsNullOrEmpty(x.Value.Processed)) + // .Select(x => x.Key) + // .ToList(); } var fileSecurity = FileSecurity; @@ -447,7 +448,7 @@ namespace ASC.Web.Files.Utils Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; - if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) + if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) { //No rights in CRM after upload before attach throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); @@ -556,7 +557,7 @@ namespace ASC.Web.Files.Utils { var folderDao = daoFactory.FolderDao; var folder = folderDao.GetFolder(newFile.FolderID); - var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; + var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; operationResult.Result = FileJsonSerializer(newFile, folderTitle); } @@ -596,36 +597,36 @@ namespace ASC.Web.Files.Utils } } - private File SaveConvertedFile(File file, string convertedFileUrl) + private File SaveConvertedFile(File file, string convertedFileUrl) { var fileSecurity = FileSecurity; - var fileDao = DaoFactory.FileDao; - var folderDao = DaoFactory.FolderDao; - File newFile = null; + var fileDao = DaoFactory.GetFileDao(); + var folderDao = DaoFactory.GetFolderDao(); + File newFile = null; var newFileTitle = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetInternalExtension(file.Title)); - if (!FilesSettingsHelper.StoreOriginalFiles && fileSecurity.CanEdit(file)) + if (!FilesSettingsHelper.StoreOriginalFiles && fileSecurity.CanEdit(file)) { - newFile = (File)file.Clone(); + newFile = (File)file.Clone(); newFile.Version++; } else { - var folderId = GlobalFolderHelper.FolderMy; + var folderId = GlobalFolderHelper.GetFolderMy(); var parent = folderDao.GetFolder(file.FolderID); if (parent != null - && fileSecurity.CanCreate(parent)) + && fileSecurity.CanCreate(parent)) { folderId = parent.ID; } if (Equals(folderId, 0)) throw new SecurityException(FilesCommonResource.ErrorMassage_FolderNotFound); - if (FilesSettingsHelper.UpdateIfExist && (parent != null && folderId != parent.ID || !file.ProviderEntry)) + if (FilesSettingsHelper.UpdateIfExist && (parent != null && !folderId.Equals(parent.ID) || !file.ProviderEntry)) { newFile = fileDao.GetFile(folderId, newFileTitle); - if (newFile != null && fileSecurity.CanEdit(newFile) && !EntryManager.FileLockedForMe(newFile.ID) && !FileTracker.IsEditing(newFile.ID)) + if (newFile != null && fileSecurity.CanEdit(newFile) && !EntryManager.FileLockedForMe(newFile.ID) && !FileTracker.IsEditing(newFile.ID)) { newFile.Version++; } @@ -637,7 +638,7 @@ namespace ASC.Web.Files.Utils if (newFile == null) { - newFile = ServiceProvider.GetService(); + newFile = ServiceProvider.GetService>(); newFile.FolderID = folderId; } } @@ -682,7 +683,7 @@ namespace ASC.Web.Files.Utils } FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title); - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); var tagDao = DaoFactory.TagDao; var tags = tagDao.GetTags(file.ID, FileEntryType.File, TagType.System).ToList(); diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index 8e9c9fa9be..eb869a4568 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -61,13 +61,13 @@ namespace ASC.Web.Files.Utils Log = optionsMonitor.CurrentValue; } - internal void ExecMarkFileAsNew(AsyncTaskData obj) + internal void ExecMarkFileAsNew(AsyncTaskData obj) { try { using var scope = ServiceProvider.CreateScope(); var fileMarker = scope.ServiceProvider.GetService(); - fileMarker.ExecMarkFileAsNew(obj); + fileMarker.ExecMarkFileAsNew(obj); } catch (Exception e) { @@ -120,17 +120,17 @@ namespace ASC.Web.Files.Utils tasks = workerQueueOptionsManager.Value; } - internal void ExecMarkFileAsNew(AsyncTaskData obj) + internal void ExecMarkFileAsNew(AsyncTaskData obj) { TenantManager.SetCurrentTenant(Convert.ToInt32(obj.TenantID)); - var folderDao = DaoFactory.FolderDao; - object parentFolderId; + var folderDao = DaoFactory.GetFolderDao(); + T parentFolderId; if (obj.FileEntry.FileEntryType == FileEntryType.File) - parentFolderId = ((File)obj.FileEntry).FolderID; + parentFolderId = ((File)obj.FileEntry).FolderID; else - parentFolderId = obj.FileEntry.ID; + parentFolderId = ((Folder)obj.FileEntry).ID; var parentFolders = folderDao.GetParentFolders(parentFolderId); parentFolders.Reverse(); @@ -142,7 +142,7 @@ namespace ASC.Web.Files.Utils { if (!userIDs.Any()) return; - parentFolders.Add(folderDao.GetFolder(GlobalFolder.GetFolderProjects(DaoFactory))); + parentFolders.Add(folderDao.GetFolder(GlobalFolder.GetFolderProjects(DaoFactory))); var entries = new List { obj.FileEntry }; entries = entries.Concat(parentFolders).ToList(); @@ -163,7 +163,7 @@ namespace ASC.Web.Files.Utils if (!userIDs.Any()) { - userIDs = filesSecurity.WhoCanRead(obj.FileEntry).Where(x => x != obj.CurrentAccountId).ToList(); + userIDs = filesSecurity.WhoCanRead(obj.FileEntry).Where(x => x != obj.CurrentAccountId).ToList(); } if (obj.FileEntry.ProviderEntry) { @@ -172,7 +172,7 @@ namespace ASC.Web.Files.Utils parentFolders.ForEach(parentFolder => filesSecurity - .WhoCanRead(parentFolder) + .WhoCanRead(parentFolder) .Where(userID => userIDs.Contains(userID) && userID != obj.CurrentAccountId) .ToList() .ForEach(userID => @@ -188,7 +188,7 @@ namespace ASC.Web.Files.Utils if (obj.FileEntry.RootFolderType == FolderType.USER) { - var folderShare = folderDao.GetFolder(GlobalFolder.GetFolderShare(DaoFactory.FolderDao)); + var folderShare = folderDao.GetFolder(GlobalFolder.GetFolderShare(DaoFactory)); foreach (var userID in userIDs) { @@ -228,7 +228,7 @@ namespace ASC.Web.Files.Utils if (obj.FileEntry.ProviderEntry) { - var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); + var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); userIDs.ForEach(userID => { if (userEntriesData.ContainsKey(userID)) @@ -281,7 +281,7 @@ namespace ASC.Web.Files.Utils tagDao.SaveTags(newTags); } - public void MarkAsNew(FileEntry fileEntry, List userIDs = null) + public void MarkAsNew(FileEntry fileEntry, List userIDs = null) { if (CoreBaseSettings.Personal) return; @@ -300,7 +300,7 @@ namespace ASC.Web.Files.Utils var projectID = path.Split('/').Last(); if (string.IsNullOrEmpty(projectID)) return; - var projectTeam = FileSecurity.WhoCanRead(fileEntry) + var projectTeam = FileSecurity.WhoCanRead(fileEntry) .Where(x => x != AuthContext.CurrentAccount.ID).ToList(); if (!projectTeam.Any()) return; @@ -313,7 +313,7 @@ namespace ASC.Web.Files.Utils tasks.Add(taskData); if (!tasks.IsStarted) - tasks.Start(FileMarkerHelper.ExecMarkFileAsNew); + tasks.Start(FileMarkerHelper.ExecMarkFileAsNew); } } @@ -349,7 +349,7 @@ namespace ASC.Web.Files.Utils var listTags = tagDao.GetNewTags(userID, (Folder)fileEntry, true).ToList(); valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.ID)).Count; - if (Equals(fileEntry.ID, userFolderId) || Equals(fileEntry.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(fileEntry.ID, GlobalFolder.GetFolderShare(DaoFactory.FolderDao))) + if (Equals(fileEntry.ID, userFolderId) || Equals(fileEntry.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(fileEntry.ID, GlobalFolder.GetFolderShare(DaoFactory))) { var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder); @@ -392,13 +392,13 @@ namespace ASC.Web.Files.Utils cacheFolderId = rootFolderId = userFolderId; else if (!rootFolder.ProviderEntry && !Equals(rootFolder.RootFolderId, userFolderId) || rootFolder.ProviderEntry && rootFolder.RootFolderCreator != userID) - cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory.FolderDao); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory); else cacheFolderId = userFolderId; } else if (rootFolder.RootFolderType == FolderType.SHARE) { - cacheFolderId = GlobalFolder.GetFolderShare(DaoFactory.FolderDao); + cacheFolderId = GlobalFolder.GetFolderShare(DaoFactory); } if (rootFolderId != null) @@ -456,7 +456,7 @@ namespace ASC.Web.Files.Utils { GlobalFolder.GetFolderMy(this, DaoFactory), GlobalFolder.GetFolderCommon(this, DaoFactory), - GlobalFolder.GetFolderShare(DaoFactory.FolderDao), + GlobalFolder.GetFolderShare(DaoFactory), GlobalFolder.GetFolderProjects(DaoFactory) }; @@ -495,26 +495,26 @@ namespace ASC.Web.Files.Utils return news; } - public List MarkedItems(Folder folder) + public List MarkedItems(Folder folder) { if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + if (!FileSecurity.CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, GlobalFolder.GetFolderTrash(DaoFactory.FolderDao))) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem); var entryTags = new Dictionary(); var tagDao = DaoFactory.TagDao; - var fileDao = DaoFactory.FileDao; - var folderDao = DaoFactory.FolderDao; + var fileDao = DaoFactory.GetFileDao(); + var folderDao = DaoFactory.GetFolderDao(); var tags = (tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folder, true) ?? new List()).ToList(); if (!tags.Any()) return new List(); - if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderShare(DaoFactory.FolderDao))) + if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderShare(DaoFactory))) { var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder); - var providerFolderTags = folderTags.Select(tag => new KeyValuePair(tag, folderDao.GetFolder(tag.EntryId))) + var providerFolderTags = folderTags.Select(tag => new KeyValuePair>(tag, folderDao.GetFolder((T)Convert.ChangeType(tag.EntryId, typeof(T))))) .Where(pair => pair.Value != null && pair.Value.ProviderEntry).ToList(); providerFolderTags.Reverse(); @@ -532,8 +532,8 @@ namespace ASC.Web.Files.Utils foreach (var tag in tags) { var entry = tag.EntryType == FileEntryType.File - ? (FileEntry)fileDao.GetFile(tag.EntryId) - : (FileEntry)folderDao.GetFolder(tag.EntryId); + ? fileDao.GetFile((T)tag.EntryId) + : (FileEntry)folderDao.GetFolder((T)tag.EntryId); if (entry != null) { entryTags.Add(entry, tag); @@ -575,16 +575,16 @@ namespace ASC.Web.Files.Utils return result; } - public IEnumerable SetTagsNew(Folder parent, IEnumerable entries) + public IEnumerable SetTagsNew(Folder parent, IEnumerable entries) { var tagDao = DaoFactory.TagDao; - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var totalTags = tagDao.GetNewTags(AuthContext.CurrentAccount.ID, parent, false).ToList(); if (totalTags.Any()) { - var parentFolderTag = Equals(GlobalFolder.GetFolderShare(DaoFactory.FolderDao), parent.ID) - ? tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folderDao.GetFolder(GlobalFolder.GetFolderShare(DaoFactory.FolderDao))).FirstOrDefault() + var parentFolderTag = Equals(GlobalFolder.GetFolderShare(DaoFactory), parent.ID) + ? tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folderDao.GetFolder(GlobalFolder.GetFolderShare(DaoFactory))).FirstOrDefault() : totalTags.FirstOrDefault(tag => tag.EntryType == FileEntryType.Folder && Equals(tag.EntryId, parent.ID)); totalTags.Remove(parentFolderTag); @@ -614,23 +614,23 @@ namespace ASC.Web.Files.Utils } var cacheFolderId = parent.ID; - var parentsList = DaoFactory.FolderDao.GetParentFolders(parent.ID); + var parentsList = DaoFactory.GetFolderDao().GetParentFolders(parent.ID); parentsList.Reverse(); parentsList.Remove(parent); if (parentsList.Any()) { var rootFolder = parentsList.Last(); - object rootFolderId = null; + T rootFolderId = default; cacheFolderId = rootFolder.ID; if (rootFolder.RootFolderType == FolderType.BUNCH) - cacheFolderId = rootFolderId = GlobalFolder.GetFolderProjects(DaoFactory); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderProjects(DaoFactory); else if (rootFolder.RootFolderType == FolderType.USER && !Equals(rootFolder.RootFolderId, GlobalFolder.GetFolderMy(this, DaoFactory))) - cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory.FolderDao); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory); if (rootFolderId != null) { - parentsList.Add(DaoFactory.FolderDao.GetFolder(rootFolderId)); + parentsList.Add(DaoFactory.GetFolderDao().GetFolder(rootFolderId)); } var fileSecurity = FileSecurity; @@ -641,7 +641,7 @@ namespace ASC.Web.Files.Utils if (parentTreeTag == null) { - if (fileSecurity.CanRead(folderFromList)) + if (fileSecurity.CanRead(folderFromList)) { tagDao.SaveTags(Tag.New(AuthContext.CurrentAccount.ID, folderFromList, -diff)); } diff --git a/products/ASC.Files/Server/Utils/FileShareLink.cs b/products/ASC.Files/Server/Utils/FileShareLink.cs index 12263b8242..fed40ac8ed 100644 --- a/products/ASC.Files/Server/Utils/FileShareLink.cs +++ b/products/ASC.Files/Server/Utils/FileShareLink.cs @@ -34,7 +34,6 @@ using ASC.Files.Core.Security; using ASC.Web.Core.Files; using ASC.Web.Files.Classes; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; namespace ASC.Web.Files.Utils @@ -61,7 +60,7 @@ namespace ASC.Web.Files.Utils FileSecurity = fileSecurity; } - public string GetLink(File file, bool withHash = true) + public string GetLink(File file, bool withHash = true) { var url = file.DownloadUrl; @@ -70,14 +69,14 @@ namespace ASC.Web.Files.Utils if (withHash) { - var linkParams = CreateKey(file.ID.ToString()); + var linkParams = CreateKey(file.ID); url += "&" + FilesLinkUtility.DocShareKey + "=" + HttpUtility.UrlEncode(linkParams); } return BaseCommonLinkUtility.GetFullAbsolutePath(url); } - public string CreateKey(string fileId) + public string CreateKey(T fileId) { return Signature.Create(fileId, Global.GetDocDbKey()); } @@ -91,12 +90,6 @@ namespace ASC.Web.Files.Utils return Signature.Read(doc ?? string.Empty, Global.GetDocDbKey()); } - public bool Check(string doc, bool checkRead, IFileDao fileDao, out File file) - { - var fileShare = Check(doc, fileDao, out file); - return (!checkRead && (fileShare == FileShare.ReadWrite || fileShare == FileShare.Review || fileShare == FileShare.FillForms || fileShare == FileShare.Comment)) - || (checkRead && fileShare != FileShare.Restrict); - } public bool Check(string doc, bool checkRead, IFileDao fileDao, out File file) { var fileShare = Check(doc, fileDao, out file); @@ -104,23 +97,6 @@ namespace ASC.Web.Files.Utils || (checkRead && fileShare != FileShare.Restrict); } - public FileShare Check(string doc, IFileDao fileDao, out File file) - { - file = null; - if (string.IsNullOrEmpty(doc)) return FileShare.Restrict; - var fileId = Parse(doc); - file = fileDao.GetFile(fileId); - if (file == null) return FileShare.Restrict; - - var filesSecurity = FileSecurity; - if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; - if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; - if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; - if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; - if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; - return FileShare.Restrict; - } - public FileShare Check(string doc, IFileDao fileDao, out File file) { file = null; @@ -130,11 +106,11 @@ namespace ASC.Web.Files.Utils if (file == null) return FileShare.Restrict; var filesSecurity = FileSecurity; - if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; - if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; - if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; - if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; - if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; + if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; + if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; + if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; + if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; + if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; return FileShare.Restrict; } } diff --git a/products/ASC.Files/Server/Utils/FileSharing.cs b/products/ASC.Files/Server/Utils/FileSharing.cs index a125ac3d14..863c4fae87 100644 --- a/products/ASC.Files/Server/Utils/FileSharing.cs +++ b/products/ASC.Files/Server/Utils/FileSharing.cs @@ -85,10 +85,10 @@ namespace ASC.Web.Files.Utils FileSharingHelper = fileSharingHelper; } - public bool SetAceObject(List aceWrappers, FileEntry entry, bool notify, string message) + public bool SetAceObject(List aceWrappers, FileEntry entry, bool notify, string message) { if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest); - if (!FileSharingHelper.CanSetAccess(entry)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); + if (!FileSharingHelper.CanSetAccess(entry)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); var fileSecurity = FileSecurity; @@ -160,7 +160,7 @@ namespace ASC.Web.Files.Utils if (entryType == FileEntryType.File) { - DocumentServiceHelper.CheckUsersForDrop((File)entry); + DocumentServiceHelper.CheckUsersForDrop((File)entry); } if (recipients.Any()) @@ -169,7 +169,7 @@ namespace ASC.Web.Files.Utils || ((Folder)entry).TotalSubFolders + ((Folder)entry).TotalFiles > 0 || entry.ProviderEntry) { - FileMarker.MarkAsNew(entry, recipients.Keys.ToList()); + FileMarker.MarkAsNew(entry, recipients.Keys.ToList()); } if (entry.RootFolderType == FolderType.USER @@ -184,7 +184,7 @@ namespace ASC.Web.Files.Utils return changed; } - public void RemoveAce(List entries) + public void RemoveAce(List entries) { var fileSecurity = FileSecurity; @@ -199,7 +199,7 @@ namespace ASC.Web.Files.Utils if (entryType == FileEntryType.File) { - DocumentServiceHelper.CheckUsersForDrop((File)entry); + DocumentServiceHelper.CheckUsersForDrop((File)entry); } FileMarker.RemoveMarkAsNew(entry); @@ -229,13 +229,13 @@ namespace ASC.Web.Files.Utils public AuthContext AuthContext { get; } public UserManager UserManager { get; } - public bool CanSetAccess(FileEntry entry) + public bool CanSetAccess(FileEntry entry) { return entry != null && (entry.RootFolderType == FolderType.COMMON && Global.IsAdministrator || entry.RootFolderType == FolderType.USER - && (Equals(entry.RootFolderId, GlobalFolderHelper.FolderMy) || FileSecurity.CanEdit(entry)) + && (Equals(entry.RootFolderId, GlobalFolderHelper.GetFolderMy()) || FileSecurity.CanEdit(entry)) && !UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)); } } @@ -274,15 +274,15 @@ namespace ASC.Web.Files.Utils Logger = optionsMonitor.CurrentValue; } - public bool CanSetAccess(FileEntry entry) + public bool CanSetAccess(FileEntry entry) { - return FileSharingHelper.CanSetAccess(entry); + return FileSharingHelper.CanSetAccess(entry); } - public List GetSharedInfo(FileEntry entry) + public List GetSharedInfo(FileEntry entry) { if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest); - if (!CanSetAccess(entry)) + if (!CanSetAccess(entry)) { Logger.ErrorFormat("User {0} can't get shared info for {1} {2}", AuthContext.CurrentAccount.ID, (entry.FileEntryType == FileEntryType.File ? "file" : "folder"), entry.ID); throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); @@ -352,7 +352,7 @@ namespace ASC.Web.Files.Utils var w = new AceWrapper { SubjectId = FileConstant.ShareLinkId, - Link = FileShareLink.GetLink((File)entry), + Link = FileShareLink.GetLink((File)entry), SubjectGroup = true, Share = linkAccess, Owner = false @@ -412,7 +412,7 @@ namespace ASC.Web.Files.Utils return result; } - public ItemList GetSharedInfo(ItemList objectIds) + public ItemList GetSharedInfo(ItemList objectIds) { if (!AuthContext.IsAuthenticated) { @@ -441,7 +441,7 @@ namespace ASC.Web.Files.Utils IEnumerable acesForObject; try { - acesForObject = GetSharedInfo(entry); + acesForObject = GetSharedInfo(entry); } catch (Exception e) { @@ -532,9 +532,9 @@ namespace ASC.Web.Files.Utils return new ItemList(result); } - public ItemList GetSharedInfoShort(string objectId) + public ItemList GetSharedInfoShort(string objectId) { - var aces = GetSharedInfo(new ItemList { objectId }); + var aces = GetSharedInfo(new ItemList { objectId }); return new ItemList( aces.Where(aceWrapper => !aceWrapper.SubjectId.Equals(FileConstant.ShareLinkId) || aceWrapper.Share != FileShare.Restrict) diff --git a/products/ASC.Files/Server/Utils/FileUploader.cs b/products/ASC.Files/Server/Utils/FileUploader.cs index 8f833f3703..1c9e2f7158 100644 --- a/products/ASC.Files/Server/Utils/FileUploader.cs +++ b/products/ASC.Files/Server/Utils/FileUploader.cs @@ -113,22 +113,22 @@ namespace ASC.Web.Files.Utils ChunkedUploadSessionHolder = chunkedUploadSessionHolder; } - public File Exec(string folderId, string title, long contentLength, Stream data) + public File Exec(T folderId, string title, long contentLength, Stream data) { return Exec(folderId, title, contentLength, data, !FilesSettingsHelper.UpdateIfExist); } - public File Exec(string folderId, string title, long contentLength, Stream data, bool createNewIfExist, bool deleteConvertStatus = true) + public File Exec(T folderId, string title, long contentLength, Stream data, bool createNewIfExist, bool deleteConvertStatus = true) { if (contentLength <= 0) throw new Exception(FilesCommonResource.ErrorMassage_EmptyFile); var file = VerifyFileUpload(folderId, title, contentLength, !createNewIfExist); - var dao = DaoFactory.FileDao; + var dao = DaoFactory.GetFileDao(); file = dao.SaveFile(file, data); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); if (FileConverter.EnableAsUploaded && FileConverter.MustConvert(file)) FileConverter.ExecAsync(file, deleteConvertStatus); @@ -136,7 +136,7 @@ namespace ASC.Web.Files.Utils return file; } - public File VerifyFileUpload(string folderId, string fileName, bool updateIfExists, string relativePath = null) + public File VerifyFileUpload(T folderId, string fileName, bool updateIfExists, string relativePath = null) { fileName = Global.ReplaceInvalidCharsAndTruncate(fileName); @@ -145,7 +145,7 @@ namespace ASC.Web.Files.Utils folderId = GetFolderId(folderId, string.IsNullOrEmpty(relativePath) ? null : relativePath.Split('/').ToList()); - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var file = fileDao.GetFile(folderId, fileName); if (updateIfExists && CanEdit(file)) @@ -160,13 +160,13 @@ namespace ASC.Web.Files.Utils return file; } - var newFile = ServiceProvider.GetService(); + var newFile = ServiceProvider.GetService>(); newFile.FolderID = folderId; newFile.Title = fileName; return newFile; } - public File VerifyFileUpload(string folderId, string fileName, long fileSize, bool updateIfExists) + public File VerifyFileUpload(T folderId, string fileName, long fileSize, bool updateIfExists) { if (fileSize <= 0) throw new Exception(FilesCommonResource.ErrorMassage_EmptyFile); @@ -181,10 +181,10 @@ namespace ASC.Web.Files.Utils return file; } - private bool CanEdit(File file) + private bool CanEdit(File file) { return file != null - && FileSecurity.CanEdit(file) + && FileSecurity.CanEdit(file) && !UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager) && !EntryManager.FileLockedForMe(file.ID) && !FileTracker.IsEditing(file.ID) @@ -192,15 +192,15 @@ namespace ASC.Web.Files.Utils && !file.Encrypted; } - private string GetFolderId(object folderId, IList relativePath) + private T GetFolderId(T folderId, IList relativePath) { - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var folder = folderDao.GetFolder(folderId); if (folder == null) throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanCreate(folder)) + if (!FileSecurity.CanCreate(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); if (relativePath != null && relativePath.Any()) @@ -213,7 +213,7 @@ namespace ASC.Web.Files.Utils if (folder == null) { - var newFolder = ServiceProvider.GetService(); + var newFolder = ServiceProvider.GetService>(); newFolder.Title = subFolderTitle; newFolder.ParentFolderID = folderId; @@ -230,7 +230,7 @@ namespace ASC.Web.Files.Utils } } - return folderId.ToString(); + return folderId; } #region chunked upload @@ -300,7 +300,7 @@ namespace ASC.Web.Files.Utils if (uploadSession.BytesUploaded == uploadSession.BytesTotal) { - FileMarker.MarkAsNew(uploadSession.File); + FileMarker.MarkAsNew(uploadSession.File); ChunkedUploadSessionHolder.RemoveSession(uploadSession); } else From c3dd78047a5b4039070d71154410c69310404cd4 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 4 Mar 2020 13:30:29 +0300 Subject: [PATCH 04/30] Files: refactoring --- .../Server/Core/Dao/Interfaces/IDaoFactory.cs | 1 + .../Server/Core/Dao/Interfaces/ITagDao.cs | 7 ++++++ .../Server/Core/Dao/TeamlabDao/AbstractDao.cs | 4 ++++ .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 4 ++++ .../Server/Core/Dao/TeamlabDao/TagDao.cs | 21 ++++++++++++---- .../Server/Core/FileStorageService.cs | 2 +- .../Server/Core/Security/FileSecurity.cs | 10 ++++++-- products/ASC.Files/Server/Helpers/Global.cs | 5 ++++ .../FileOperations/FileMarkAsReadOperation.cs | 2 +- .../WCFService/Wrappers/DataWrapper.cs | 2 +- products/ASC.Files/Server/Utils/FileMarker.cs | 24 +++++++++---------- 11 files changed, 60 insertions(+), 22 deletions(-) diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs index e55c58592e..39844206c6 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs @@ -39,6 +39,7 @@ namespace ASC.Files.Core IFileDao GetFileDao(); ITagDao TagDao { get; } + ITagDao GetTagDao(); ISecurityDao SecurityDao { get; } diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs index a1e092a612..9624ecb53a 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs @@ -29,6 +29,13 @@ using System.Collections.Generic; namespace ASC.Files.Core { + public interface ITagDao : ITagDao + { + IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch); + + IEnumerable GetTags(T entryID, FileEntryType entryType, TagType tagType); + } + public interface ITagDao { IEnumerable GetTags(TagType tagType, IEnumerable fileEntries); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/AbstractDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/AbstractDao.cs index ff303c011a..8beb4cd0d5 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/AbstractDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/AbstractDao.cs @@ -169,6 +169,10 @@ namespace ASC.Files.Core.Data return result; } + protected int MappingID(int id) + { + return id; + } protected object MappingID(object id) { return MappingID(id, false); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index ee540574c4..fbc17d2682 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -60,6 +60,10 @@ namespace ASC.Files.Core.Data { return ServiceProvider.GetService>(); } + public ITagDao GetTagDao() + { + return ServiceProvider.GetService>(); + } } public static class DaoFactoryExtention diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs index 88e64a173f..e132f947bf 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs @@ -41,7 +41,7 @@ using ASC.Web.Studio.Utility; namespace ASC.Files.Core.Data { - internal class TagDao : AbstractDao, ITagDao + internal class TagDao : AbstractDao, ITagDao { private static readonly object syncRoot = new object(); @@ -89,6 +89,11 @@ namespace ASC.Files.Core.Data } public IEnumerable GetTags(object entryID, FileEntryType entryType, TagType tagType) + { + throw new NotImplementedException(); + } + + public IEnumerable GetTags(int entryID, FileEntryType entryType, TagType tagType) { var q = Query(FilesDbContext.Tag) .Join(FilesDbContext.TagLink, r => r.Id, l => l.TagId, (tag, link) => new TagLinkData { Tag = tag, Link = link }) @@ -388,7 +393,7 @@ namespace ASC.Files.Core.Data var tags = fileEntries.Select(r => new DbFilesTagLink { TenantId = TenantID, - EntryId = MappingID(r.ID).ToString(), + EntryId = MappingID((r as File)?.ID ?? (r as Folder)?.ID).ToString(), EntryType = (r.FileEntryType == FileEntryType.File) ? FileEntryType.File : FileEntryType.Folder }) .ToList(); @@ -416,12 +421,17 @@ namespace ASC.Files.Core.Data public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - if (parentFolder == null || parentFolder.ID == null) + throw new NotImplementedException(); + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + if (parentFolder == null || parentFolder.ID == 0) throw new ArgumentException("folderId"); var result = new List(); - var monitorFolderIds = new[] { parentFolder.ID }.AsEnumerable(); + var monitorFolderIds = new object[] { parentFolder.ID }.AsEnumerable(); var getBaseSqlQuery = new Func>(() => { @@ -554,7 +564,7 @@ namespace ASC.Files.Core.Data result.AddRange(FromQuery(newTagsForFolders)); - var where = (deepSearch ? monitorFolderIds.ToArray() : new[] { parentFolder.ID }) + var where = (deepSearch ? monitorFolderIds.ToArray() : new object[] { parentFolder.ID }) .Select(r => r.ToString()) .ToList(); @@ -635,6 +645,7 @@ namespace ASC.Files.Core.Data public static DIHelper AddTagDaoService(this DIHelper services) { services.TryAddScoped(); + services.TryAddScoped, TagDao>(); return services .AddUserManagerService() .AddFilesDbContextService() diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index dd7077fcf7..afe38bc0b5 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -305,7 +305,7 @@ namespace ASC.Web.Files.Services.WCFService Entries = new ItemList(entries.ToList()), FolderPathParts = new ItemList(breadCrumbs.Select(f => f.ID)), FolderInfo = parent, - RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew() + RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew() }; return result; diff --git a/products/ASC.Files/Server/Core/Security/FileSecurity.cs b/products/ASC.Files/Server/Core/Security/FileSecurity.cs index 58db3d8e3b..5174c14477 100644 --- a/products/ASC.Files/Server/Core/Security/FileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/FileSecurity.cs @@ -324,7 +324,7 @@ namespace ASC.Files.Core.Security var result = new List(entries.Count()); // save entries order - var order = entries.Select((f, i) => new { Id = f.UniqID, Pos = i }).ToDictionary(e => e.Id, e => e.Pos); + var order = entries.Select((f, i) => new { Id = GetUniqID(f), Pos = i }).ToDictionary(e => e.Id, e => e.Pos); // common or my files Func filter = @@ -539,8 +539,14 @@ namespace ASC.Files.Core.Security } // restore entries order - result.Sort((x, y) => order[x.UniqID].CompareTo(order[y.UniqID])); + result.Sort((x, y) => order[GetUniqID(x)].CompareTo(order[GetUniqID(y)])); return result; + + //TODO + string GetUniqID(FileEntry f) + { + return (f as File)?.UniqID ?? (f as Folder)?.UniqID; + }; } public void Share(object entryId, FileEntryType entryType, Guid @for, FileShare share) diff --git a/products/ASC.Files/Server/Helpers/Global.cs b/products/ASC.Files/Server/Helpers/Global.cs index 470989724c..ced0b009ac 100644 --- a/products/ASC.Files/Server/Helpers/Global.cs +++ b/products/ASC.Files/Server/Helpers/Global.cs @@ -306,6 +306,11 @@ namespace ASC.Web.Files.Classes internal static readonly IDictionary UserRootFolderCache = new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ + public T GetFolderMy(FileMarker fileMarker, IDaoFactory daoFactory) + { + return (T)Convert.ChangeType(GetFolderMy(fileMarker, daoFactory), typeof(T)); + } + public int GetFolderMy(FileMarker fileMarker, IDaoFactory daoFactory) { if (!AuthContext.IsAuthenticated) return default; diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs index fa47880d72..79b402e651 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs @@ -94,7 +94,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations }); var newrootfolder = fileMarker - .GetRootFoldersIdMarkedAsNew() + .GetRootFoldersIdMarkedAsNew() .Select(item => string.Format("new_{{\"key\"? \"{0}\", \"value\"? \"{1}\"}}", item.Key, item.Value)); Status += string.Join(FileOperation.SPLIT_CHAR, newrootfolder.ToArray()); diff --git a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs index df012b7c9e..c17db31a12 100644 --- a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs +++ b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs @@ -47,6 +47,6 @@ namespace ASC.Web.Files.Services.WCFService public Folder FolderInfo { get; set; } [DataMember(IsRequired = false, Name = "root_folders_id_marked_as_new")] - public Dictionary RootFoldersIdMarkedAsNew { get; set; } + public Dictionary RootFoldersIdMarkedAsNew { get; set; } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index eb869a4568..c144bd9049 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -450,18 +450,18 @@ namespace ASC.Web.Files.Utils } } - public Dictionary GetRootFoldersIdMarkedAsNew() + public Dictionary GetRootFoldersIdMarkedAsNew() { - var rootIds = new List + var rootIds = new List { - GlobalFolder.GetFolderMy(this, DaoFactory), - GlobalFolder.GetFolderCommon(this, DaoFactory), - GlobalFolder.GetFolderShare(DaoFactory), - GlobalFolder.GetFolderProjects(DaoFactory) + GlobalFolder.GetFolderMy(this, DaoFactory), + GlobalFolder.GetFolderCommon(this, DaoFactory), + GlobalFolder.GetFolderShare(DaoFactory), + GlobalFolder.GetFolderProjects(DaoFactory) }; - var requestIds = new List(); - var news = new Dictionary(); + var requestIds = new List(); + var news = new Dictionary(); rootIds.ForEach(rootId => { @@ -479,8 +479,8 @@ namespace ASC.Web.Files.Utils if (requestIds.Any()) { IEnumerable requestTags; - var tagDao = DaoFactory.TagDao; - var folderDao = DaoFactory.FolderDao; + var tagDao = DaoFactory.GetTagDao(); + var folderDao = DaoFactory.GetFolderDao(); requestTags = tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folderDao.GetFolders(requestIds.ToArray())); requestIds.ForEach(requestId => @@ -489,7 +489,7 @@ namespace ASC.Web.Files.Utils InsertToCahce(requestId, requestTag == null ? 0 : requestTag.Count); }); - news = news.Concat(requestTags.ToDictionary(x => x.EntryId, x => x.Count)).ToDictionary(x => x.Key, x => x.Value); + news = news.Concat(requestTags.ToDictionary(x => (T)Convert.ChangeType(x.EntryId, typeof(T)), x => x.Count)).ToDictionary(x => x.Key, x => x.Value); } return news; @@ -577,7 +577,7 @@ namespace ASC.Web.Files.Utils public IEnumerable SetTagsNew(Folder parent, IEnumerable entries) { - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var folderDao = DaoFactory.GetFolderDao(); var totalTags = tagDao.GetNewTags(AuthContext.CurrentAccount.ID, parent, false).ToList(); From ece437cbc07322e9ed50b193954835174bd02b36 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 4 Mar 2020 17:40:05 +0300 Subject: [PATCH 05/30] Files: refactoring --- .../Server/Controllers/FilesController.cs | 45 ++- .../Server/Core/Dao/Interfaces/IDaoFactory.cs | 7 +- .../Server/Core/Dao/Interfaces/IFileDao.cs | 269 ------------- .../Server/Core/Dao/Interfaces/IFolderDao.cs | 253 ------------ .../Server/Core/Dao/Interfaces/ITagDao.cs | 19 +- .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 15 +- .../Server/Core/Dao/TeamlabDao/FileDao.cs | 189 +-------- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 164 +------- .../Server/Core/Dao/TeamlabDao/SecurityDao.cs | 16 +- .../Server/Core/Dao/TeamlabDao/TagDao.cs | 205 +--------- .../ASC.Files/Server/Core/Entries/File.cs | 41 +- .../Server/Core/Entries/FileEntry.cs | 18 +- .../ASC.Files/Server/Core/Entries/Folder.cs | 39 +- products/ASC.Files/Server/Core/Entries/Tag.cs | 4 +- .../Server/Core/FileStorageService.cs | 376 +++++++++--------- .../Server/Core/Search/FilesWrapper.cs | 12 +- .../Server/Core/Search/FoldersWrapper.cs | 4 +- .../Server/Core/Security/FileSecurity.cs | 178 ++++----- .../Server/Core/Security/IFileSecurity.cs | 16 +- .../Server/Core/Security/ISecurityDao.cs | 10 +- .../Server/Helpers/DocuSignHelper.cs | 6 +- .../Server/Helpers/FilesMessageService.cs | 8 +- products/ASC.Files/Server/Helpers/Global.cs | 12 +- .../ASC.Files/Server/Helpers/PathProvider.cs | 14 +- .../HttpHandlers/ChunkedUploaderHandler.cs | 4 +- .../Server/HttpHandlers/FileHandler.ashx.cs | 18 +- .../Server/HttpHandlers/SearchHandler.cs | 6 +- .../Server/Model/FileEntryWrapper.cs | 4 +- .../ASC.Files/Server/Model/FileWrapper.cs | 2 +- .../ASC.Files/Server/Model/FolderWrapper.cs | 2 +- .../Services/DocumentService/Configuration.cs | 6 +- .../DocumentService/DocumentServiceHelper.cs | 27 +- .../DocumentService/DocumentServiceTracker.cs | 13 +- .../Services/NotifyService/NotifyClient.cs | 12 +- .../WCFService/FileEntrySerializer.cs | 10 +- .../FileOperations/FileDeleteOperation.cs | 8 +- .../FileOperations/FileDownloadOperation.cs | 4 +- .../FileOperations/FileMarkAsReadOperation.cs | 2 +- .../FileOperations/FileMoveCopyOperation.cs | 22 +- .../FileOperations/FileOperation.cs | 4 +- .../WCFService/IFileStorageService.cs | 39 +- .../WCFService/Wrappers/DataWrapper.cs | 2 +- .../ASC.Files/Server/Utils/EntryManager.cs | 73 ++-- .../ASC.Files/Server/Utils/FileConverter.cs | 60 ++- products/ASC.Files/Server/Utils/FileMarker.cs | 161 ++++---- .../ASC.Files/Server/Utils/FileShareLink.cs | 10 +- .../ASC.Files/Server/Utils/FileSharing.cs | 43 +- .../ASC.Files/Server/Utils/FileUploader.cs | 16 +- 48 files changed, 672 insertions(+), 1796 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index ebf16cbd60..debbf06fe3 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -78,8 +78,9 @@ namespace ASC.Api.Documents public class FilesController : ControllerBase { private readonly ApiContext ApiContext; - private readonly FileStorageService FileStorageService; + private readonly FileStorageService FileStorageService; + public FileStorageService FileStorageServiceInt { get; } public GlobalFolderHelper GlobalFolderHelper { get; } public FileWrapperHelper FileWrapperHelper { get; } public FilesSettingsHelper FilesSettingsHelper { get; } @@ -118,7 +119,8 @@ namespace ASC.Api.Documents /// public FilesController( ApiContext context, - FileStorageService fileStorageService, + FileStorageService fileStorageService, + FileStorageService fileStorageServiceInt, GlobalFolderHelper globalFolderHelper, FileWrapperHelper fileWrapperHelper, FilesSettingsHelper filesSettingsHelper, @@ -153,6 +155,7 @@ namespace ASC.Api.Documents { ApiContext = context; FileStorageService = fileStorageService; + FileStorageServiceInt = fileStorageServiceInt; GlobalFolderHelper = globalFolderHelper; FileWrapperHelper = fileWrapperHelper; FilesSettingsHelper = filesSettingsHelper; @@ -669,7 +672,7 @@ namespace ASC.Api.Documents { using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) { - var file = FileUploader.Exec(folderId, + var file = FileUploader.Exec(folderId.ToString(), title.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? title : (title + extension), memStream.Length, memStream); return FileWrapperHelper.Get(file); @@ -834,7 +837,7 @@ namespace ASC.Api.Documents [Read("file/{fileId:int}")] public FileWrapper GetFileInfo(int fileId, int version = -1) { - var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); + var file = FileStorageServiceInt.GetFile(fileId, version).NotFoundIfNull("File not found"); return FileWrapperHelper.Get(file); } @@ -905,7 +908,7 @@ namespace ASC.Api.Documents [Read("file/{fileId}/checkconversion")] public IEnumerable CheckConversion(string fileId, bool start) { - return FileStorageService.CheckConversion(new ItemList> + return FileStorageService.CheckConversion(new ItemList> { new ItemList { fileId, "0", start.ToString() } }) @@ -969,7 +972,7 @@ namespace ASC.Api.Documents var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); - var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); + var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); return entries.Select(x => FileWrapperHelper.Get((File)x)); } @@ -1031,7 +1034,7 @@ namespace ASC.Api.Documents itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); } /// @@ -1109,7 +1112,7 @@ namespace ASC.Api.Documents itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); + return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); } /// @@ -1121,7 +1124,7 @@ namespace ASC.Api.Documents [Update("fileops/emptytrash")] public IEnumerable EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } /// @@ -1163,7 +1166,7 @@ namespace ASC.Api.Documents [Read("file/{fileId}/share")] public IEnumerable GetFileSecurityInfo(string fileId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); return fileShares.Select(FileShareWrapperHelper.Get); } @@ -1177,7 +1180,7 @@ namespace ASC.Api.Documents [Read("folder/{folderId}/share")] public IEnumerable GetFolderSecurityInfo(string folderId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); return fileShares.Select(FileShareWrapperHelper.Get); } @@ -1206,7 +1209,7 @@ namespace ASC.Api.Documents Aces = list, Message = sharingMessage }; - FileStorageService.SetAceObject(aceCollection, notify); + FileStorageService.SetAceObject(aceCollection, notify); } return GetFileSecurityInfo(fileId); } @@ -1236,7 +1239,7 @@ namespace ASC.Api.Documents Aces = list, Message = sharingMessage }; - FileStorageService.SetAceObject(aceCollection, notify); + FileStorageService.SetAceObject(aceCollection, notify); } return GetFolderSecurityInfo(folderId); @@ -1258,7 +1261,7 @@ namespace ASC.Api.Documents itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - FileStorageService.RemoveAce(itemList); + FileStorageService.RemoveAce(itemList); return true; } @@ -1279,7 +1282,7 @@ namespace ASC.Api.Documents var file = GetFileInfo(fileId); var objectId = "file_" + file.Id; - var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); if (sharedInfo == null || sharedInfo.Share != share) { var list = new ItemList @@ -1296,8 +1299,8 @@ namespace ASC.Api.Documents Entries = new ItemList { objectId }, Aces = list }; - FileStorageService.SetAceObject(aceCollection, false); - sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + FileStorageService.SetAceObject(aceCollection, false); + sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); } return sharedInfo.Link; @@ -1394,7 +1397,7 @@ namespace ASC.Api.Documents ProviderKey = providerKey, }; - var folder = FileStorageService.SaveThirdParty(thirdPartyParams); + var folder = FileStorageService.SaveThirdParty(thirdPartyParams); return FolderWrapperHelper.Get(folder); } @@ -1418,7 +1421,7 @@ namespace ASC.Api.Documents /// Get third party folder /// Connected providers folder [Read("thirdparty/common")] - public IEnumerable GetCommonThirdPartyFolders() + public IEnumerable> GetCommonThirdPartyFolders() { var parent = FileStorageService.GetFolder(GlobalFolderHelper.FolderCommon.ToString()); return EntryManager.GetThirpartyFolders(parent); @@ -1437,7 +1440,7 @@ namespace ASC.Api.Documents [Delete("thirdparty/{providerId:int}")] public object DeleteThirdParty(int providerId) { - return FileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture)); + return FileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture)); } @@ -1573,7 +1576,7 @@ namespace ASC.Api.Documents } var startIndex = Convert.ToInt32(ApiContext.StartIndex); - var items = FileStorageService.GetFolderItems( + var items = FileStorageServiceInt.GetFolderItems( folderId, startIndex, Convert.ToInt32(ApiContext.Count) - 1, //NOTE: in ApiContext +1 diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs index 39844206c6..b92d762bb7 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IDaoFactory.cs @@ -30,18 +30,13 @@ namespace ASC.Files.Core { public interface IDaoFactory { - IFolderDao FolderDao { get; } - IFolderDao GetFolderDao(); - IFileDao FileDao { get; } - IFileDao GetFileDao(); - ITagDao TagDao { get; } ITagDao GetTagDao(); - ISecurityDao SecurityDao { get; } + ISecurityDao GetSecurityDao(); IProviderDao ProviderDao { get; } } diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs index e314a214ec..78d851de0d 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs @@ -299,273 +299,4 @@ namespace ASC.Files.Core #endregion } - - /// - /// Interface encapsulates access toFolderId files - /// - public interface IFileDao - { - /// - /// Clear the application cache for the specific file - /// - void InvalidateCache(object fileId); - - /// - /// Receive file - /// - /// file id - /// - File GetFile(object fileId); - - /// - /// Receive file - /// - /// file id - /// file version - /// - File GetFile(object fileId, int fileVersion); - - /// - /// Receive file - /// - /// folder id - /// file name - /// - /// file - /// - File GetFile(object parentId, string title); - - /// - /// Receive last file without forcesave - /// - /// file id - /// - /// - File GetFileStable(object fileId, int fileVersion = -1); - - /// - /// Returns all versions of the file - /// - /// - /// - List GetFileHistory(object fileId); - - /// - /// Gets the file (s) by ID (s) - /// - /// id file - /// - List GetFiles(object[] fileIds); - - /// - /// Gets the file (s) by ID (s) for share - /// - /// id file - /// - /// - /// - /// - /// - /// - List GetFilesForShare(object[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent); - - /// - /// - /// - /// - /// - List GetFiles(object parentId); - - /// - /// Get files in folder - /// - /// folder id - /// - /// filterType type - /// - /// - /// - /// - /// - /// list of files - /// - /// Return only the latest versions of files of a folder - /// - List GetFiles(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false); - - /// - /// Get stream of file - /// - /// - /// Stream - Stream GetFileStream(File file); - - /// - /// Get stream of file - /// - /// - /// - /// Stream - Stream GetFileStream(File file, long offset); - - /// - /// Get presigned uri - /// - /// - /// - /// Stream uri - Uri GetPreSignedUri(File file, TimeSpan expires); - - /// - /// Check is supported PreSignedUri - /// - /// - /// Stream uri - bool IsSupportedPreSignedUri(File file); - - /// - /// Saves / updates the version of the file - /// and save stream of file - /// - /// - /// - /// - /// - /// Updates the file if: - /// - The file comes with the given id - /// - The file with that name in the folder / container exists - /// - /// Save in all other cases - /// - File SaveFile(File file, Stream fileStream); - - /// - /// - /// - /// - /// - /// - File ReplaceFileVersion(File file, Stream fileStream); - - /// - /// Deletes a file including all previous versions - /// - /// file id - void DeleteFile(object fileId); - - /// - /// Checks whether or not file - /// - /// file name - /// folder id - /// Returns true if the file exists, otherwise false - bool IsExist(string title, object folderId); - - /// - /// Moves a file or set of files in a folder - /// - /// file id - /// The ID of the destination folder - object MoveFile(object fileId, object toFolderId); - - /// - /// Copy the files in a folder - /// - /// file id - /// The ID of the destination folder - File CopyFile(object fileId, object toFolderId); - - /// - /// Rename file - /// - /// - /// new name - object FileRename(File file, string newTitle); - - /// - /// Update comment file - /// - /// file id - /// file version - /// new comment - string UpdateComment(object fileId, int fileVersion, string comment); - - /// - /// Complete file version - /// - /// file id - /// file version - void CompleteVersion(object fileId, int fileVersion); - - /// - /// Continue file version - /// - /// file id - /// file version - void ContinueVersion(object fileId, int fileVersion); - - /// - /// Check the need to use the trash before removing - /// - /// - /// - bool UseTrashForRemove(File file); - - #region chunking - - ChunkedUploadSession CreateUploadSession(File file, long contentLength); - - void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength); - - void AbortUploadSession(ChunkedUploadSession uploadSession); - - #endregion - - #region Only in TMFileDao - - /// - /// Set created by - /// - /// - /// - void ReassignFiles(object[] fileIds, Guid newOwnerId); - - /// - /// Search files in SharedWithMe & Projects - /// - /// - /// - /// - /// - /// - /// - /// - List GetFiles(object[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent); - - /// - /// Search the list of files containing text - /// Only in TMFileDao - /// - /// search text - /// - /// list of files - IEnumerable Search(string text, bool bunch = false); - - /// - /// Checks whether file exists on storage - /// - /// file - /// - bool IsExistOnStorage(File file); - - void SaveEditHistory(File file, string changes, Stream differenceStream); - - List GetEditHistory(DocumentServiceHelper documentServiceHelper, object fileId, int fileVersion = 0); - - Stream GetDifferenceStream(File file); - - bool ContainChanges(object fileId, int fileVersion); - - #endregion - } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs index 0d05668308..3c3d82d3b0 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs @@ -282,257 +282,4 @@ namespace ASC.Files.Core #endregion } - - public interface IFolderDao - { - /// - /// Get folder by id. - /// - /// folder id - /// folder - Folder GetFolder(object folderId); - - /// - /// Returns the folder with the given name and id of the root - /// - /// - /// - /// - Folder GetFolder(string title, object parentId); - - /// - /// Gets the root folder - /// - /// folder id - /// root folder - Folder GetRootFolder(object folderId); - - /// - /// Gets the root folder - /// - /// file id - /// root folder - Folder GetRootFolderByFile(object fileId); - - /// - /// Get a list of folders in current folder. - /// - /// - List GetFolders(object parentId); - - /// - /// Get a list of folders. - /// - /// - /// - /// - /// - /// - /// - /// - /// - List GetFolders(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false); - - /// - /// Gets the folder (s) by ID (s) - /// - /// - /// - /// - /// - /// - /// - /// - /// - List GetFolders(object[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true); - - /// - /// Get folder, contains folder with id - /// - /// folder id - /// - List GetParentFolders(object folderId); - - /// - /// save or update folder - /// - /// - /// - object SaveFolder(Folder folder); - - /// - /// delete folder - /// - /// folder id - void DeleteFolder(object folderId); - - /// - /// move folder - /// - /// folder id - /// destination folder id - /// - object MoveFolder(object folderId, object toFolderId, CancellationToken? cancellationToken); - - /// - /// copy folder - /// - /// - /// - /// - /// - /// - Folder CopyFolder(object folderId, object toFolderId, CancellationToken? cancellationToken); - - /// - /// Validate the transfer operation directory to another directory. - /// - /// - /// - /// - /// Returns pair of file ID, file name, in which the same name. - /// - IDictionary CanMoveOrCopy(object[] folderIds, object to); - - /// - /// Rename folder - /// - /// - /// new name - object RenameFolder(Folder folder, string newTitle); - - /// - /// Gets the number of files and folders to the container in your - /// - /// folder id - /// - int GetItemsCount(object folderId); - - /// - /// Check folder on emptiness - /// - /// folder id - /// - bool IsEmpty(object folderId); - - /// - /// Check the need to use the trash before removing - /// - /// - /// - bool UseTrashForRemove(Folder folder); - - /// - /// Check the need to use recursion for operations - /// - /// - /// - /// - bool UseRecursiveOperation(object folderId, object toRootFolderId); - - /// - /// Check the possibility to calculate the number of subitems - /// - /// - /// - bool CanCalculateSubitems(object entryId); - - /// - /// Returns maximum size of file which can be uploaded to specific folder - /// - /// Id of the folder - /// Determines whenever supposed upload will be chunked (true) or not (false) - /// Maximum size of file which can be uploaded to folder - long GetMaxUploadSize(object folderId, bool chunkedUpload = false); - - #region Only for TMFolderDao - - /// - /// Set created by - /// - /// - /// - void ReassignFolders(object[] folderIds, Guid newOwnerId); - - /// - /// Search the list of folders containing text in title - /// Only in TMFolderDao - /// - /// - /// - /// - IEnumerable Search(string text, bool bunch = false); - - /// - /// Only in TMFolderDao - /// - /// - /// - /// - /// - /// - object GetFolderID(string module, string bunch, string data, bool createIfNotExists); - - IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists); - - /// - /// Returns id folder "Shared Documents" - /// Only in TMFolderDao - /// - /// - object GetFolderIDCommon(bool createIfNotExists); - - /// - /// Returns id folder "My Documents" - /// Only in TMFolderDao - /// - /// - /// - /// - object GetFolderIDUser(bool createIfNotExists, Guid? userId = null); - - /// - /// Returns id folder "Shared with me" - /// Only in TMFolderDao - /// - /// - /// - object GetFolderIDShare(bool createIfNotExists); - - /// - /// Returns id folder "Trash" - /// Only in TMFolderDao - /// - /// - /// - /// - object GetFolderIDTrash(bool createIfNotExists, Guid? userId = null); - - /// - /// Returns id folder "Projects" - /// Only in TMFolderDao - /// - /// - /// - object GetFolderIDProjects(bool createIfNotExists); - - - /// - /// Return id of related object - /// Only in TMFolderDao - /// - /// - /// - string GetBunchObjectID(object folderID); - - /// - /// Return ids of related objects - /// Only in TMFolderDao - /// - /// - /// - Dictionary GetBunchObjectIDs(List folderIDs); - - #endregion - } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs index 9624ecb53a..75e5fc676c 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/ITagDao.cs @@ -29,16 +29,17 @@ using System.Collections.Generic; namespace ASC.Files.Core { - public interface ITagDao : ITagDao + public interface ITagDao { IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch); IEnumerable GetTags(T entryID, FileEntryType entryType, TagType tagType); - } - public interface ITagDao - { - IEnumerable GetTags(TagType tagType, IEnumerable fileEntries); + IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries); + + IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries); + + IEnumerable GetNewTags(Guid subject, FileEntry fileEntry); IEnumerable GetTags(Guid owner, TagType tagType); @@ -46,12 +47,6 @@ namespace ASC.Files.Core IEnumerable GetTags(string[] names, TagType tagType); - IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch); - - IEnumerable GetNewTags(Guid subject, IEnumerable fileEntries); - - IEnumerable GetNewTags(Guid subject, FileEntry fileEntry); - IEnumerable SaveTags(IEnumerable tag); IEnumerable SaveTags(Tag tag); @@ -63,7 +58,5 @@ namespace ASC.Files.Core void RemoveTags(IEnumerable tag); void RemoveTags(Tag tag); - - IEnumerable GetTags(object entryID, FileEntryType entryType, TagType tagType); } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index fbc17d2682..4930874b7a 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -36,19 +36,11 @@ namespace ASC.Files.Core.Data public class DaoFactory : IDaoFactory { public IServiceProvider ServiceProvider { get; } - public IFileDao FileDao { get; } - public IFolderDao FolderDao { get; } - public ITagDao TagDao { get; } - public ISecurityDao SecurityDao { get; } public IProviderDao ProviderDao { get; } - public DaoFactory(IServiceProvider serviceProvider, IFileDao fileDao, IFolderDao folderDao, ITagDao tagDao, ISecurityDao securityDao) + public DaoFactory(IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; - FileDao = fileDao; - FolderDao = folderDao; - TagDao = tagDao; - SecurityDao = securityDao; } public IFileDao GetFileDao() @@ -64,6 +56,11 @@ namespace ASC.Files.Core.Data { return ServiceProvider.GetService>(); } + + public ISecurityDao GetSecurityDao() + { + return ServiceProvider.GetService>(); + } } public static class DaoFactoryExtention diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index 7c74085ff9..2bd56ba45e 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -51,14 +51,14 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Core.Data { - public class FileDao : AbstractDao, IFileDao, IFileDao + public class FileDao : AbstractDao, IFileDao { private static readonly object syncRoot = new object(); public FactoryIndexer FactoryIndexer { get; } public GlobalStore GlobalStore { get; } public GlobalSpace GlobalSpace { get; } public GlobalFolder GlobalFolder { get; } - public IFolderDao FolderDao { get; } + public IFolderDao FolderDao { get; } public ChunkedUploadSessionHolder ChunkedUploadSessionHolder { get; } public FileDao( @@ -78,7 +78,7 @@ namespace ASC.Files.Core.Data GlobalStore globalStore, GlobalSpace globalSpace, GlobalFolder globalFolder, - IFolderDao folderDao, + IFolderDao folderDao, ChunkedUploadSessionHolder chunkedUploadSessionHolder) : base( dbContextManager, @@ -102,42 +102,22 @@ namespace ASC.Files.Core.Data ChunkedUploadSessionHolder = chunkedUploadSessionHolder; } - public void InvalidateCache(object fileId) - { - throw new NotImplementedException(); - } - public void InvalidateCache(int fileId) { } - public File GetFile(object fileId) - { - throw new NotImplementedException(); - } - public File GetFile(int fileId) { var query = GetFileQuery(r => r.Id == fileId && r.CurrentVersion); return FromQueryWithShared(query).SingleOrDefault(); } - public File GetFile(object fileId, int fileVersion) - { - throw new NotImplementedException(); - } - public File GetFile(int fileId, int fileVersion) { var query = GetFileQuery(r => r.Id == fileId && r.Version == fileVersion); return FromQueryWithShared(query).SingleOrDefault(); } - public File GetFile(object parentId, string title) - { - throw new NotImplementedException(); - } - public File GetFile(int parentId, string title) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(title); @@ -148,11 +128,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query).FirstOrDefault(); } - public File GetFileStable(object fileId, int fileVersion = -1) - { - throw new NotImplementedException(); - } - public File GetFileStable(int fileId, int fileVersion = -1) { var query = GetFileQuery(r => r.Id == fileId && r.Forcesave == ForcesaveType.None); @@ -167,11 +142,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query).SingleOrDefault(); } - public List GetFileHistory(object fileId) - { - throw new NotImplementedException(); - } - public List> GetFileHistory(int fileId) { var query = GetFileQuery(r => r.Id == fileId).OrderByDescending(r => r.Version); @@ -179,11 +149,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query); } - public List GetFiles(object[] fileIds) - { - throw new NotImplementedException(); - } - public List> GetFiles(int[] fileIds) { if (fileIds == null || fileIds.Length == 0) return new List>(); @@ -193,11 +158,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query); } - public List GetFilesForShare(object[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) - { - throw new NotImplementedException(); - } - public List> GetFilesForShare(int[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) { if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); @@ -253,11 +213,6 @@ namespace ASC.Files.Core.Data } - public List GetFiles(object parentId) - { - throw new NotImplementedException(); - } - public List GetFiles(int parentId) { var query = GetFileQuery(r => r.FolderId == parentId && r.CurrentVersion).Select(r => r.Id); @@ -268,11 +223,6 @@ namespace ASC.Files.Core.Data .ToList(); } - public List GetFiles(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) - { - throw new NotImplementedException(); - } - public List> GetFiles(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) { if (filterType == FilterType.FoldersOnly) return new List>(); @@ -362,21 +312,11 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(q); } - public Stream GetFileStream(File file, long offset) - { - throw new NotImplementedException(); - } - public Stream GetFileStream(File file, long offset) { return GlobalStore.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file), (int)offset); } - public Uri GetPreSignedUri(File file, TimeSpan expires) - { - throw new NotImplementedException(); - } - public Uri GetPreSignedUri(File file, TimeSpan expires) { return GlobalStore.GetStore().GetPreSignedUri(string.Empty, GetUniqFilePath(file), expires, @@ -386,31 +326,16 @@ namespace ASC.Files.Core.Data }); } - public bool IsSupportedPreSignedUri(File file) - { - throw new NotImplementedException(); - } - public bool IsSupportedPreSignedUri(File file) { return GlobalStore.GetStore().IsSupportedPreSignedUri; } - public Stream GetFileStream(File file) - { - throw new NotImplementedException(); - } - public Stream GetFileStream(File file) { return GetFileStream(file, 0); } - public File SaveFile(File file, Stream fileStream) - { - throw new NotImplementedException(); - } - public File SaveFile(File file, Stream fileStream) { if (file == null) @@ -547,11 +472,6 @@ namespace ASC.Files.Core.Data return GetFile(file.ID); } - public File ReplaceFileVersion(File file, Stream fileStream) - { - throw new NotImplementedException(); - } - public File ReplaceFileVersion(File file, Stream fileStream) { if (file == null) throw new ArgumentNullException("file"); @@ -691,11 +611,6 @@ namespace ASC.Files.Core.Data GlobalStore.GetStore().Save(string.Empty, GetUniqFilePath(file), stream, file.Title); } - public void DeleteFile(object fileId) - { - throw new NotImplementedException(); - } - public void DeleteFile(int fileId) { DeleteFile(fileId, true); @@ -752,11 +667,6 @@ namespace ASC.Files.Core.Data .Any(); } - public object MoveFile(object fileId, object toFolderId) - { - throw new NotImplementedException(); - } - public int MoveFile(int fileId, int toFolderId) { if (fileId == default) return default; @@ -777,7 +687,7 @@ namespace ASC.Files.Core.Data { f.FolderId = toFolderId; - if (GlobalFolder.GetFolderTrash(FolderDao).Equals(toFolderId)) + if (GlobalFolder.GetFolderTrash(FolderDao).Equals(toFolderId)) { f.ModifiedBy = AuthContext.CurrentAccount.ID; f.ModifiedOn = DateTime.UtcNow; @@ -809,11 +719,6 @@ namespace ASC.Files.Core.Data return fileId; } - public File CopyFile(object fileId, object toFolderId) - { - throw new NotImplementedException(); - } - public File CopyFile(int fileId, int toFolderId) { var file = GetFile(fileId); @@ -838,11 +743,6 @@ namespace ASC.Files.Core.Data return null; } - public object FileRename(File file, string newTitle) - { - throw new NotImplementedException(); - } - public int FileRename(File file, string newTitle) { newTitle = Global.ReplaceInvalidCharsAndTruncate(newTitle); @@ -860,11 +760,6 @@ namespace ASC.Files.Core.Data return file.ID; } - public string UpdateComment(object fileId, int fileVersion, string comment) - { - throw new NotImplementedException(); - } - public string UpdateComment(int fileId, int fileVersion, string comment) { comment ??= string.Empty; @@ -882,11 +777,6 @@ namespace ASC.Files.Core.Data return comment; } - public void CompleteVersion(object fileId, int fileVersion) - { - - } - public void CompleteVersion(int fileId, int fileVersion) { var toUpdate = Query(FilesDbContext.Files) @@ -901,11 +791,6 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); } - public void ContinueVersion(object fileId, int fileVersion) - { - throw new NotImplementedException(); - } - public void ContinueVersion(int fileId, int fileVersion) { using var tx = FilesDbContext.Database.BeginTransaction(); @@ -931,11 +816,6 @@ namespace ASC.Files.Core.Data tx.Commit(); } - public bool UseTrashForRemove(File file) - { - throw new NotImplementedException(); - } - public bool UseTrashForRemove(File file) { return file.RootFolderType != FolderType.TRASH; @@ -963,7 +843,7 @@ namespace ASC.Files.Core.Data public string GetUniqFileVersionPath(int fileId, int version) { - return fileId != null + return fileId != 0 ? string.Format("{0}/v{1}", GetUniqFileDirectory(fileId), version) : null; } @@ -975,21 +855,11 @@ namespace ASC.Files.Core.Data #region chunking - public ChunkedUploadSession CreateUploadSession(File file, long contentLength) - { - throw new NotImplementedException(); - } - public ChunkedUploadSession CreateUploadSession(File file, long contentLength) { return ChunkedUploadSessionHolder.CreateUploadSession(file, contentLength); } - public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) - { - throw new NotImplementedException(); - } - public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) { if (!uploadSession.UseChunks) @@ -1024,11 +894,6 @@ namespace ASC.Files.Core.Data return file; } - public void AbortUploadSession(ChunkedUploadSession uploadSession) - { - throw new NotImplementedException(); - } - public void AbortUploadSession(ChunkedUploadSession uploadSession) { ChunkedUploadSessionHolder.AbortUploadSession(uploadSession); @@ -1060,11 +925,6 @@ namespace ASC.Files.Core.Data #region Only in TMFileDao - public void ReassignFiles(object[] fileIds, Guid newOwnerId) - { - throw new NotImplementedException(); - } - public void ReassignFiles(int[] fileIds, Guid newOwnerId) { var toUpdate = Query(FilesDbContext.Files) @@ -1079,11 +939,6 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); } - public List GetFiles(object[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) - { - throw new NotImplementedException(); - } - public List> GetFiles(int[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) { if (parentIds == null || parentIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); @@ -1141,12 +996,7 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(q); } - public IEnumerable Search(string searchText, bool bunch) - { - throw new NotImplementedException(); - } - - IEnumerable> IFileDao.Search(string searchText, bool bunch) + public IEnumerable> Search(string searchText, bool bunch) { if (FactoryIndexer.TrySelectIds(s => s.MatchAll(searchText), out var ids)) { @@ -1176,11 +1026,6 @@ namespace ASC.Files.Core.Data GlobalStore.GetStore().DeleteDirectory(GetUniqFileDirectory(fileId)); } - public bool IsExistOnStorage(File file) - { - throw new NotImplementedException(); - } - public bool IsExistOnStorage(File file) { return GlobalStore.GetStore().IsFile(GetUniqFilePath(file)); @@ -1188,11 +1033,6 @@ namespace ASC.Files.Core.Data private const string DiffTitle = "diff.zip"; - public void SaveEditHistory(File file, string changes, Stream differenceStream) - { - throw new NotImplementedException(); - } - public void SaveEditHistory(File file, string changes, Stream differenceStream) { if (file == null) throw new ArgumentNullException("file"); @@ -1215,11 +1055,6 @@ namespace ASC.Files.Core.Data GlobalStore.GetStore().Save(string.Empty, GetUniqFilePath(file, DiffTitle), differenceStream, DiffTitle); } - public List GetEditHistory(DocumentServiceHelper documentServiceHelper, object fileId, int fileVersion = 0) - { - throw new NotImplementedException(); - } - public List GetEditHistory(DocumentServiceHelper documentServiceHelper, int fileId, int fileVersion = 0) { var query = Query(FilesDbContext.Files) @@ -1254,21 +1089,11 @@ namespace ASC.Files.Core.Data .ToList(); } - public Stream GetDifferenceStream(File file) - { - throw new NotImplementedException(); - } - public Stream GetDifferenceStream(File file) { return GlobalStore.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file, DiffTitle)); } - public bool ContainChanges(object fileId, int fileVersion) - { - throw new NotImplementedException(); - } - public bool ContainChanges(int fileId, int fileVersion) { return Query(FilesDbContext.Files) @@ -1432,9 +1257,7 @@ namespace ASC.Files.Core.Data { public static DIHelper AddFileDaoService(this DIHelper services) { - services.TryAddScoped(); services.TryAddScoped, FileDao>(); - services.TryAddTransient(); services.TryAddTransient>(); return services diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index 3aff80867d..9f8b770588 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -50,7 +50,7 @@ using Microsoft.Extensions.Options; namespace ASC.Files.Core.Data { - public class FolderDao : AbstractDao, IFolderDao, IFolderDao + public class FolderDao : AbstractDao, IFolderDao { private const string my = "my"; private const string common = "common"; @@ -97,22 +97,12 @@ namespace ASC.Files.Core.Data Logger = options.Get("ASC.Files"); } - public Folder GetFolder(object folderId) - { - throw new NotImplementedException(); - } - public Folder GetFolder(int folderId) { var query = GetFolderQuery(r => r.Id == folderId); return FromQueryWithShared(query).SingleOrDefault(); } - public Folder GetFolder(string title, object parentId) - { - throw new NotImplementedException(); - } - public Folder GetFolder(string title, int parentId) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException(title); @@ -123,10 +113,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query).FirstOrDefault(); } - public Folder GetRootFolder(object folderId) - { - throw new NotImplementedException(); - } public Folder GetRootFolder(int folderId) { var id = FilesDbContext.Tree @@ -140,10 +126,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query).SingleOrDefault(); } - public Folder GetRootFolderByFile(object fileId) - { - throw new NotImplementedException(); - } public Folder GetRootFolderByFile(int fileId) { var subq = Query(FilesDbContext.Files) @@ -161,20 +143,11 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(query).SingleOrDefault(); } - public List GetFolders(object parentId) - { - throw new NotImplementedException(); - } public List> GetFolders(int parentId) { return GetFolders(parentId, default, default, false, default, string.Empty); } - public List GetFolders(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) - { - throw new NotImplementedException(); - } - public List> GetFolders(int parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) { if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension @@ -242,11 +215,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(q); } - public List GetFolders(object[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) - { - throw new NotImplementedException(); - } - public List> GetFolders(int[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) { if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension @@ -298,11 +266,6 @@ namespace ASC.Files.Core.Data return checkShare ? FromQueryWithShared(q) : FromQuery(q); } - public List GetParentFolders(object folderId) - { - throw new NotImplementedException(); - } - public List> GetParentFolders(int folderId) { var q = GetFolderQuery() @@ -314,11 +277,6 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(q); } - public object SaveFolder(Folder folder) - { - throw new NotImplementedException(); - } - public int SaveFolder(Folder folder) { if (folder == null) throw new ArgumentNullException("folder"); @@ -414,10 +372,6 @@ namespace ASC.Files.Core.Data .Any(); } - public void DeleteFolder(object folderId) - { - throw new NotImplementedException(); - } public void DeleteFolder(int id) { if (id == default) throw new ArgumentNullException("folderId"); @@ -474,10 +428,6 @@ namespace ASC.Files.Core.Data FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = (int)id }); } - public object MoveFolder(object folderId, object toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } public int MoveFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { using (var tx = FilesDbContext.Database.BeginTransaction()) @@ -542,10 +492,6 @@ namespace ASC.Files.Core.Data return folderId; } - public Folder CopyFolder(object folderId, object toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } public Folder CopyFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { var folder = GetFolder(folderId); @@ -569,10 +515,6 @@ namespace ASC.Files.Core.Data return copy; } - public IDictionary CanMoveOrCopy(object[] folderIds, object to) - { - throw new NotImplementedException(); - } public IDictionary CanMoveOrCopy(int[] folderIds, int to) { var result = new Dictionary(); @@ -624,11 +566,6 @@ namespace ASC.Files.Core.Data return result; } - public object RenameFolder(Folder folder, string newTitle) - { - throw new NotImplementedException(); - } - public int RenameFolder(Folder folder, string newTitle) { var toUpdate = Query(FilesDbContext.Folders) @@ -644,10 +581,6 @@ namespace ASC.Files.Core.Data return folder.ID; } - public int GetItemsCount(object folderId) - { - throw new NotImplementedException(); - } public int GetItemsCount(int folderId) { @@ -675,51 +608,26 @@ namespace ASC.Files.Core.Data return count; } - public bool IsEmpty(object folderId) - { - throw new NotImplementedException(); - } - public bool IsEmpty(int folderId) { return GetItemsCount(folderId) == 0; } - public bool UseTrashForRemove(Folder folder) - { - throw new NotImplementedException(); - } - public bool UseTrashForRemove(Folder folder) { return folder.RootFolderType != FolderType.TRASH && folder.FolderType != FolderType.BUNCH; } - public bool UseRecursiveOperation(object folderId, object toRootFolderId) - { - throw new NotImplementedException(); - } - public bool UseRecursiveOperation(int folderId, int toRootFolderId) { return true; } - public bool CanCalculateSubitems(object entryId) - { - throw new NotImplementedException(); - } - public bool CanCalculateSubitems(int entryId) { return true; } - public long GetMaxUploadSize(object folderId, bool chunkedUpload) - { - throw new NotImplementedException(); - } - public long GetMaxUploadSize(int folderId, bool chunkedUpload) { var tmp = long.MaxValue; @@ -747,11 +655,6 @@ namespace ASC.Files.Core.Data #region Only for TMFolderDao - public void ReassignFolders(object[] folderIds, Guid newOwnerId) - { - throw new NotImplementedException(); - } - public void ReassignFolders(int[] folderIds, Guid newOwnerId) { var toUpdate = Query(FilesDbContext.Folders) @@ -765,12 +668,8 @@ namespace ASC.Files.Core.Data FilesDbContext.SaveChanges(); } - public IEnumerable Search(string text, bool bunch) - { - throw new NotImplementedException(); - } - IEnumerable> IFolderDao.Search(string text, bool bunch) + public IEnumerable> Search(string text, bool bunch) { return Search(text).Where(f => bunch ? f.RootFolderType == FolderType.BUNCH @@ -791,12 +690,7 @@ namespace ASC.Files.Core.Data return FromQueryWithShared(q); } - public virtual IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) - { - throw new NotImplementedException(); - } - - IEnumerable IFolderDao.GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -863,12 +757,7 @@ namespace ASC.Files.Core.Data return folderIds; } - public virtual object GetFolderID(string module, string bunch, string data, bool createIfNotExists) - { - throw new NotImplementedException(); - } - - int IFolderDao.GetFolderID(string module, string bunch, string data, bool createIfNotExists) + public int GetFolderID(string module, string bunch, string data, bool createIfNotExists) { if (string.IsNullOrEmpty(module)) throw new ArgumentNullException("module"); if (string.IsNullOrEmpty(bunch)) throw new ArgumentNullException("bunch"); @@ -934,53 +823,27 @@ namespace ASC.Files.Core.Data return newFolderId; } - - public object GetFolderIDProjects(bool createIfNotExists) - { - throw new NotImplementedException(); - } - int IFolderDao.GetFolderIDProjects(bool createIfNotExists) { return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, projects, null, createIfNotExists); } - public object GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) - { - throw new NotImplementedException(); - } - - int IFolderDao.GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) + public int GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) { return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, trash, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); } - public object GetFolderIDCommon(bool createIfNotExists) - { - throw new NotImplementedException(); - } - - int IFolderDao.GetFolderIDCommon(bool createIfNotExists) + public int GetFolderIDCommon(bool createIfNotExists) { return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, common, null, createIfNotExists); } - public object GetFolderIDUser(bool createIfNotExists, Guid? userId = null) - { - throw new NotImplementedException(); - } - - int IFolderDao.GetFolderIDUser(bool createIfNotExists, Guid? userId = null) + public int GetFolderIDUser(bool createIfNotExists, Guid? userId = null) { return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, my, (userId ?? AuthContext.CurrentAccount.ID).ToString(), createIfNotExists); } - public object GetFolderIDShare(bool createIfNotExists) - { - return GetFolderID(FileConstant.ModuleId, share, null, createIfNotExists); - } - - int IFolderDao.GetFolderIDShare(bool createIfNotExists) + public int GetFolderIDShare(bool createIfNotExists) { return (this as IFolderDao).GetFolderID(FileConstant.ModuleId, share, null, createIfNotExists); } @@ -1096,10 +959,6 @@ namespace ASC.Files.Core.Data return result; } - public string GetBunchObjectID(object folderID) - { - throw new NotImplementedException(); - } public string GetBunchObjectID(int folderID) { return Query(FilesDbContext.BunchObjects) @@ -1108,11 +967,6 @@ namespace ASC.Files.Core.Data .FirstOrDefault(); } - public Dictionary GetBunchObjectIDs(List folderIDs) - { - throw new NotImplementedException(); - } - public Dictionary GetBunchObjectIDs(List folderIDs) { return Query(FilesDbContext.BunchObjects) @@ -1185,9 +1039,7 @@ namespace ASC.Files.Core.Data { public static DIHelper AddFolderDaoService(this DIHelper services) { - services.TryAddScoped(); services.TryAddScoped, FolderDao>(); - services.TryAddTransient(); services.TryAddTransient>(); return services diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs index df391d3f72..b3c50166c5 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs @@ -42,7 +42,7 @@ using ASC.Web.Studio.Utility; namespace ASC.Files.Core.Data { - internal class SecurityDao : AbstractDao, ISecurityDao + internal class SecurityDao : AbstractDao, ISecurityDao { public SecurityDao(UserManager userManager, DbContextManager dbContextManager, @@ -180,7 +180,7 @@ namespace ASC.Files.Core.Data return FromQuery(q); } - public IEnumerable GetPureShareRecords(IEnumerable entries) + public IEnumerable GetPureShareRecords(IEnumerable> entries) { if (entries == null) return new List(); @@ -195,7 +195,7 @@ namespace ASC.Files.Core.Data return GetPureShareRecordsDb(files, folders); } - public IEnumerable GetPureShareRecords(FileEntry entry) + public IEnumerable GetPureShareRecords(FileEntry entry) { if (entry == null) return new List(); @@ -228,7 +228,7 @@ namespace ASC.Files.Core.Data /// /// /// - public IEnumerable GetShares(IEnumerable entries) + public IEnumerable GetShares(IEnumerable> entries) { if (entries == null) return new List(); @@ -248,7 +248,7 @@ namespace ASC.Files.Core.Data /// /// /// - public IEnumerable GetShares(FileEntry entry) + public IEnumerable GetShares(FileEntry entry) { if (entry == null) return new List(); @@ -259,13 +259,13 @@ namespace ASC.Files.Core.Data return SaveFilesAndFoldersForShare(files, foldersInt); } - private void SelectFilesAndFoldersForShare(FileEntry entry, ICollection files, ICollection folders, ICollection foldersInt) + private void SelectFilesAndFoldersForShare(FileEntry entry, ICollection files, ICollection folders, ICollection foldersInt) { object folderId; if (entry.FileEntryType == FileEntryType.File) { var fileId = MappingID(entry.ID); - folderId = ((File)entry).FolderID; + folderId = ((File)entry).FolderID; if (!files.Contains(fileId.ToString())) files.Add(fileId.ToString()); } else @@ -369,7 +369,7 @@ namespace ASC.Files.Core.Data { public static DIHelper AddSecurityDaoService(this DIHelper services) { - services.TryAddScoped(); + services.TryAddScoped, SecurityDao>(); return services .AddUserManagerService() diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs index e132f947bf..8b6386fd62 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs @@ -73,7 +73,7 @@ namespace ASC.Files.Core.Data { } - public IEnumerable GetTags(TagType tagType, IEnumerable fileEntries) + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) { var filesId = fileEntries.Where(e => e.FileEntryType == FileEntryType.File).Select(e => MappingID(e.ID).ToString()).ToList(); var foldersId = fileEntries.Where(e => e.FileEntryType == FileEntryType.Folder).Select(e => MappingID(e.ID).ToString()).ToList(); @@ -88,11 +88,6 @@ namespace ASC.Files.Core.Data return FromQuery(q); } - public IEnumerable GetTags(object entryID, FileEntryType entryType, TagType tagType) - { - throw new NotImplementedException(); - } - public IEnumerable GetTags(int entryID, FileEntryType entryType, TagType tagType) { var q = Query(FilesDbContext.Tag) @@ -381,12 +376,12 @@ namespace ASC.Files.Core.Data } } - public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) { - return GetNewTags(subject, new List(1) { fileEntry }); + return GetNewTags(subject, new List>(1) { fileEntry }); } - public IEnumerable GetNewTags(Guid subject, IEnumerable fileEntries) + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) { List result; @@ -419,198 +414,9 @@ namespace ASC.Files.Core.Data return result; } - public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) - { - throw new NotImplementedException(); - } - public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - if (parentFolder == null || parentFolder.ID == 0) - throw new ArgumentException("folderId"); - - var result = new List(); - - var monitorFolderIds = new object[] { parentFolder.ID }.AsEnumerable(); - - var getBaseSqlQuery = new Func>(() => - { - var fnResult = Query(FilesDbContext.Tag) - .Join(FilesDbContext.TagLink, r => r.Id, l => l.TagId, (tag, link) => new TagLinkData { Tag = tag, Link = link }) - .Where(r => r.Link.TenantId == r.Tag.TenantId) - .Where(r => r.Tag.Flag == TagType.New) - .Distinct(); - - if (subject != Guid.Empty) - { - fnResult = fnResult.Where(r => r.Tag.Owner == subject); - } - - return fnResult; - }); - - var tempTags = Enumerable.Empty(); - - if (parentFolder.FolderType == FolderType.SHARE) - { - var shareQuery = - new Func>(() => getBaseSqlQuery().Where( - r => FilesDbContext.Security - .Where(a => a.TenantId == r.Link.TenantId) - .Where(a => a.EntryId == r.Link.EntryId) - .Where(a => a.EntryType == r.Link.EntryType) - .Any())); - - var tmpShareFileTags = - shareQuery() - .Join(FilesDbContext.Files, r => r.Link.EntryId, f => f.Id.ToString(), (tagLink, file) => new { tagLink, file }) - .Where(r => r.file.TenantId == r.tagLink.Link.TenantId) - .Where(r => r.file.CreateBy != subject) - .Where(r => r.tagLink.Link.EntryType == FileEntryType.File) - .Select(r => new - { - r.tagLink, - root = FilesDbContext.Folders - .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) - .Where(x => x.folder.TenantId == r.file.TenantId) - .Where(x => x.tree.FolderId == r.file.FolderId) - .OrderByDescending(r => r.tree.Level) - .Select(r => r.folder) - .FirstOrDefault() - }) - .Where(r => r.root.FolderType == FolderType.USER) - .Select(r => r.tagLink); - - tempTags = tempTags.Concat(FromQuery(tmpShareFileTags)); - - - var tmpShareFolderTags = - shareQuery() - .Join(FilesDbContext.Folders, r => r.Link.EntryId, f => f.Id.ToString(), (tagLink, folder) => new { tagLink, folder }) - .Where(r => r.folder.TenantId == r.tagLink.Link.TenantId) - .Where(r => r.folder.CreateBy != subject) - .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) - .Select(r => new - { - r.tagLink, - root = FilesDbContext.Folders - .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) - .Where(x => x.folder.TenantId == r.folder.TenantId) - .Where(x => x.tree.FolderId == r.folder.ParentId) - .OrderByDescending(r => r.tree.Level) - .Select(r => r.folder) - .FirstOrDefault() - }) - .Where(r => r.root.FolderType == FolderType.USER) - .Select(r => r.tagLink); - - tempTags = tempTags.Concat(FromQuery(tmpShareFolderTags)); - - var tmpShareSboxTags = - shareQuery() - .Join(FilesDbContext.ThirdpartyIdMapping, r => r.Link.EntryId, r => r.HashId, (tagLink, mapping) => new { tagLink, mapping }) - .Where(r => r.mapping.TenantId == r.tagLink.Link.TenantId) - .Join(FilesDbContext.ThirdpartyAccount, r => r.mapping.TenantId, r => r.TenantId, (tagLinkMapping, account) => new { tagLinkMapping.tagLink, tagLinkMapping.mapping, account }) - .Where(r => r.account.UserId != subject) - .Where(r => r.account.FolderType == FolderType.USER) - .Where(r => - r.mapping.Id.StartsWith("sbox-" + r.account.Id) || - r.mapping.Id.StartsWith("box-" + r.account.Id) || - r.mapping.Id.StartsWith("dropbox-" + r.account.Id) || - r.mapping.Id.StartsWith("spoint-" + r.account.Id) || - r.mapping.Id.StartsWith("drive-" + r.account.Id) || - r.mapping.Id.StartsWith("onedrive-" + r.account.Id) - ) - .Select(r => r.tagLink); - - tempTags = tempTags.Concat(FromQuery(tmpShareSboxTags)); - } - else if (parentFolder.FolderType == FolderType.Projects) - { - var q = getBaseSqlQuery() - .Join(FilesDbContext.BunchObjects, r => r.Link.TenantId, r => r.TenantId, (tagLink, bunch) => new { tagLink, bunch }) - .Where(r => r.bunch.LeftNode == r.tagLink.Link.EntryId) - .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) - .Where(r => r.bunch.RightNode.StartsWith("projects/project/")) - .Select(r => r.tagLink); - tempTags = tempTags.Concat(FromQuery(q)); - } - - if (tempTags.Any()) - { - if (!deepSearch) return tempTags; - - monitorFolderIds = monitorFolderIds.Concat(tempTags.Where(x => x.EntryType == FileEntryType.Folder).Select(x => x.EntryId)); - result.AddRange(tempTags); - } - - var monitorFolderIdsInt = monitorFolderIds.Select(r => Convert.ToInt32(r)).ToList(); - var subFoldersSqlQuery = - FilesDbContext.Tree - .Where(r => monitorFolderIdsInt.Any(a => r.ParentId == a)); - - if (!deepSearch) - { - subFoldersSqlQuery = subFoldersSqlQuery.Where(r => r.Level == 1); - } - - monitorFolderIds = monitorFolderIds.Concat(subFoldersSqlQuery.Select(r => r.FolderId).ToList().ConvertAll(r => (object)r)); - - var monitorFolderIdsStrings = monitorFolderIds.Select(r => r.ToString()).ToList(); - - var newTagsForFolders = getBaseSqlQuery() - .Where(r => monitorFolderIdsStrings.Any(a => r.Link.EntryId == a)) - .Where(r => r.Link.EntryType == FileEntryType.Folder); - - result.AddRange(FromQuery(newTagsForFolders)); - - var where = (deepSearch ? monitorFolderIds.ToArray() : new object[] { parentFolder.ID }) - .Select(r => r.ToString()) - .ToList(); - - var newTagsForFiles = - getBaseSqlQuery() - .Join(FilesDbContext.Files, r => r.Link.EntryId, r => r.Id.ToString(), (tagLink, file) => new { tagLink, file }) - .Where(r => r.file.TenantId == r.tagLink.Link.TenantId) - .Where(r => where.Any(a => r.file.FolderId.ToString() == a)) - .Where(r => r.tagLink.Link.EntryType == FileEntryType.File) - .Select(r => r.tagLink); - - result.AddRange(FromQuery(newTagsForFiles)); - - if (parentFolder.FolderType == FolderType.USER || parentFolder.FolderType == FolderType.COMMON) - { - var folderType = parentFolder.FolderType; - - var querySelect = FilesDbContext.ThirdpartyAccount - .Where(r => r.TenantId == TenantID) - .Where(r => r.FolderType == folderType); - - if (folderType == FolderType.USER) - { - querySelect = querySelect.Where(r => r.UserId == subject); - } - - var folderIds = querySelect.Select(r => r.Id).ToList(); - var thirdpartyFolderIds = folderIds.ConvertAll(r => "sbox-" + r) - .Concat(folderIds.ConvertAll(r => $"box-{r}")) - .Concat(folderIds.ConvertAll(r => $"dropbox-{r}")) - .Concat(folderIds.ConvertAll(r => $"spoint-{r}")) - .Concat(folderIds.ConvertAll(r => $"drive-{r}")) - .Concat(folderIds.ConvertAll(r => $"onedrive-{r}")); - - var newTagsForSBox = getBaseSqlQuery() - .Join(FilesDbContext.ThirdpartyIdMapping, r => r.Link.EntryId, r => r.HashId, (tagLink, mapping) => new { tagLink, mapping }) - .Where(r => r.mapping.TenantId == r.tagLink.Link.TenantId) - .Where(r => thirdpartyFolderIds.Any(a => r.mapping.Id == a)) - .Where(r => r.tagLink.Tag.Owner == subject) - .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) - .Select(r => r.tagLink); - - result.AddRange(FromQuery(newTagsForSBox)); - } - - return result; + throw new NotImplementedException(); } protected List FromQuery(IQueryable dbFilesTags) @@ -644,7 +450,6 @@ namespace ASC.Files.Core.Data { public static DIHelper AddTagDaoService(this DIHelper services) { - services.TryAddScoped(); services.TryAddScoped, TagDao>(); return services .AddUserManagerService() diff --git a/products/ASC.Files/Server/Core/Entries/File.cs b/products/ASC.Files/Server/Core/Entries/File.cs index 0f8f2c2d57..2ff9abf8e6 100644 --- a/products/ASC.Files/Server/Core/Entries/File.cs +++ b/products/ASC.Files/Server/Core/Entries/File.cs @@ -54,41 +54,10 @@ namespace ASC.Files.Core [EnumMember] IsEditingAlone = 0x10 } - public class File : File - { - [DataMember(Name = "id")] - public new T ID { get; set; } - - public new T FolderID { get; set; } - - private T _folderIdDisplay; - - [DataMember(Name = "folder_id")] - public new T FolderIdDisplay - { - get - { - if (_folderIdDisplay != null) return _folderIdDisplay; - - return FolderID; - } - set { _folderIdDisplay = value; } - } - - public new string UniqID - { - get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } - } - - public File(Global global, FilesLinkUtility filesLinkUtility, FileUtility fileUtility, FileConverter fileConverter) : base(global, filesLinkUtility, fileUtility, fileConverter) - { - } - } - [Serializable] [DataContract(Name = "file", Namespace = "")] [DebuggerDisplay("{Title} ({ID} v{Version})")] - public class File : FileEntry + public class File : FileEntry { private FileStatus _status; @@ -106,7 +75,7 @@ namespace ASC.Files.Core FileConverter = fileConverter; } - public object FolderID { get; set; } + public T FolderID { get; set; } [DataMember(Name = "version")] public int Version { get; set; } @@ -250,10 +219,10 @@ namespace ASC.Files.Core public FileUtility FileUtility { get; } public FileConverter FileConverter { get; } - private object _folderIdDisplay; + private T _folderIdDisplay; [DataMember(Name = "folder_id")] - public override object FolderIdDisplay + public override T FolderIdDisplay { get { @@ -264,7 +233,7 @@ namespace ASC.Files.Core set { _folderIdDisplay = value; } } - public static string Serialize(File file) + public static string Serialize(File file) { using (var ms = new FileEntrySerializer().ToXml(file)) { diff --git a/products/ASC.Files/Server/Core/Entries/FileEntry.cs b/products/ASC.Files/Server/Core/Entries/FileEntry.cs index 5526ede63b..6748734040 100644 --- a/products/ASC.Files/Server/Core/Entries/FileEntry.cs +++ b/products/ASC.Files/Server/Core/Entries/FileEntry.cs @@ -33,10 +33,8 @@ using ASC.Web.Files.Classes; namespace ASC.Files.Core { [DataContract(Name = "entry", Namespace = "")] - [KnownType(typeof(Folder))] - [KnownType(typeof(File))] [Serializable] - public abstract class FileEntry : ICloneable + public abstract class FileEntry : ICloneable { public FileEntry(Global global) { @@ -44,7 +42,7 @@ namespace ASC.Files.Core } [DataMember(Name = "id")] - public object ID { get; set; } + public T ID { get; set; } [DataMember(Name = "title", IsRequired = true)] public virtual string Title { get; set; } @@ -99,7 +97,7 @@ namespace ASC.Files.Core public string ProviderKey { get; set; } [DataMember(Name = "folder_id")] - public abstract object FolderIdDisplay + public abstract T FolderIdDisplay { get; set; @@ -118,7 +116,7 @@ namespace ASC.Files.Core public Guid RootFolderCreator { get; set; } - public object RootFolderId { get; set; } + public T RootFolderId { get; set; } public abstract bool IsNew { get; set; } @@ -136,8 +134,12 @@ namespace ASC.Files.Core public override bool Equals(object obj) { - var f = obj as FileEntry; - return f != null && Equals(f.ID, ID); + return obj is FileEntry f && Equals(f.ID, ID); + } + + public bool Equals(FileEntry obj) + { + return Equals(obj.ID, ID); } public override int GetHashCode() diff --git a/products/ASC.Files/Server/Core/Entries/Folder.cs b/products/ASC.Files/Server/Core/Entries/Folder.cs index 222b132a0e..8962ec8a93 100644 --- a/products/ASC.Files/Server/Core/Entries/Folder.cs +++ b/products/ASC.Files/Server/Core/Entries/Folder.cs @@ -50,44 +50,13 @@ namespace ASC.Files.Core [EnumMember] Projects = 8 } - public class Folder : Folder - { - [DataMember(Name = "id")] - public new T ID { get; set; } - - public new T ParentFolderID { get; set; } - - private T _folderIdDisplay; - - [DataMember(Name = "folder_id")] - public new T FolderIdDisplay - { - get - { - if (_folderIdDisplay != null) return _folderIdDisplay; - - return ParentFolderID; - } - set { _folderIdDisplay = value; } - } - - public new string UniqID - { - get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } - } - - public Folder(Global global) : base(global) - { - } - } - [DataContract(Name = "folder", Namespace = "")] [DebuggerDisplay("{Title} ({ID})")] - public class Folder : FileEntry + public class Folder : FileEntry { public FolderType FolderType { get; set; } - public object ParentFolderID { get; set; } + public T ParentFolderID { get; set; } [DataMember(Name = "total_files")] public int TotalFiles { get; set; } @@ -110,10 +79,10 @@ namespace ASC.Files.Core set { NewForMe = Convert.ToInt32(value); } } - private object _folderIdDisplay; + private T _folderIdDisplay; [DataMember(Name = "folder_id")] - public override object FolderIdDisplay + public override T FolderIdDisplay { get { diff --git a/products/ASC.Files/Server/Core/Entries/Tag.cs b/products/ASC.Files/Server/Core/Entries/Tag.cs index 37d2db8a4a..b0f39c11a1 100644 --- a/products/ASC.Files/Server/Core/Entries/Tag.cs +++ b/products/ASC.Files/Server/Core/Entries/Tag.cs @@ -78,12 +78,12 @@ namespace ASC.Files.Core } - public static Tag New(Guid owner, FileEntry entry) + public static Tag New(Guid owner, FileEntry entry) { return New(owner, entry, 1); } - public static Tag New(Guid owner, FileEntry entry, int count) + public static Tag New(Guid owner, FileEntry entry, int count) { return new Tag("new", TagType.New, owner, entry, count); } diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index afe38bc0b5..c8494d5b94 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -66,13 +66,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; using UrlShortener = ASC.Web.Core.Utility.UrlShortener; namespace ASC.Web.Files.Services.WCFService { - public class FileStorageService //: IFileStorageService + public class FileStorageService //: IFileStorageService { private static readonly FileEntrySerializer serializer = new FileEntrySerializer(); public Global Global { get; } @@ -111,7 +110,7 @@ namespace ASC.Web.Files.Services.WCFService public FileOperationsManagerHelper FileOperationsManagerHelper { get; } public UrlShortener UrlShortener { get; } public IServiceProvider ServiceProvider { get; } - public FileSharingAceHelper FileSharingAceHelper { get; } + public FileSharingAceHelper FileSharingAceHelper { get; } public ApiContext ApiContext { get; } public ILog Logger { get; set; } @@ -153,7 +152,7 @@ namespace ASC.Web.Files.Services.WCFService FileOperationsManagerHelper fileOperationsManagerHelper, UrlShortener urlShortener, IServiceProvider serviceProvider, - FileSharingAceHelper fileSharingAceHelper, + FileSharingAceHelper fileSharingAceHelper, ApiContext apiContext) { Global = global; @@ -197,20 +196,20 @@ namespace ASC.Web.Files.Services.WCFService Logger = optionMonitor.Get("ASC.Files"); } - public Folder GetFolder(T folderId) + public Folder GetFolder(T folderId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder); return folder; } - public ItemList> GetFolders(T parentId) + public ItemList> GetFolders(T parentId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); try { @@ -223,23 +222,23 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList GetPath(T folderId) + public ItemList GetPath(T folderId) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); return new ItemList(EntryManager.GetBreadCrumbs(folderId, folderDao).Select(f => f.ID)); } - public DataWrapper GetFolderItems(T parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public DataWrapper GetFolderItems(T parentId, int from, int count, FilterType filter, bool subjectGroup, string ssubject, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(ssubject) ? Guid.Empty : new Guid(ssubject); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); Folder parent = null; try @@ -257,7 +256,7 @@ namespace ASC.Web.Files.Services.WCFService } ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanRead(parent), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + ErrorIf(!FileSecurity.CanRead(parent), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); ErrorIf(parent.RootFolderType == FolderType.TRASH && !Equals(parent.ID, GlobalFolderHelper.FolderTrash), FilesCommonResource.ErrorMassage_ViewTrashItem); if (orderBy != null) @@ -273,7 +272,7 @@ namespace ASC.Web.Files.Services.WCFService orderBy.SortedBy = SortedByType.New; int total; - IEnumerable entries; + IEnumerable> entries; try { entries = EntryManager.GetEntries(parent, from, count, filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, orderBy, out total); @@ -295,14 +294,14 @@ namespace ASC.Web.Files.Services.WCFService parent.ParentFolderID = prevVisible.ID; } - parent.Shareable = FileSharing.CanSetAccess(parent) || parent.FolderType == FolderType.SHARE; + parent.Shareable = FileSharing.CanSetAccess(parent) || parent.FolderType == FolderType.SHARE; - entries = entries.Where(x => x.FileEntryType == FileEntryType.Folder || !FileConverter.IsConverting((File)x)); + entries = entries.Where(x => x.FileEntryType == FileEntryType.Folder || !FileConverter.IsConverting((File)x)); var result = new DataWrapper { Total = total, - Entries = new ItemList(entries.ToList()), + Entries = new ItemList>(entries.ToList()), FolderPathParts = new ItemList(breadCrumbs.Select(f => f.ID)), FolderInfo = parent, RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew() @@ -311,27 +310,27 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetFolderItemsXml(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public object GetFolderItemsXml(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); var response = new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StreamContent(serializer.ToXml(folderItems)) + Content = new StreamContent(serializer.ToXml(folderItems)) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return response; } - public ItemList GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string search) + public ItemList> GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string search) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); - var entries = Enumerable.Empty(); + var entries = Enumerable.Empty>(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var folders = folderDao.GetFolders(foldersId.ToArray()); folders = FileSecurity.FilterRead(folders).ToList(); entries = entries.Concat(folders); @@ -348,7 +347,7 @@ namespace ASC.Web.Files.Services.WCFService { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) + && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -357,26 +356,26 @@ namespace ASC.Web.Files.Services.WCFService { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) + && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) { folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } } - EntryManager.SetFileStatus(entries.OfType().Where(r => r.ID != null).ToList()); + EntryManager.SetFileStatus(entries.OfType>().Where(r => r.ID != null).ToList()); - return new ItemList(entries); + return new ItemList>(entries); } - public Folder CreateNewFolder(T parentId, string title) + public Folder CreateNewFolder(T parentId, string title) { if (string.IsNullOrEmpty(title) || parentId == null) throw new ArgumentException(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var parent = folderDao.GetFolder(parentId); ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanCreate(parent), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(parent), FilesCommonResource.ErrorMassage_SecurityException_Create); try { @@ -396,14 +395,14 @@ namespace ASC.Web.Files.Services.WCFService } } - public Folder FolderRename(T folderId, string title) + public Folder FolderRename(T folderId, string title) { var tagDao = GetTagDao(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(folderId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); - if (!FileSecurity.CanDelete(folder) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); + ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); + if (!FileSecurity.CanDelete(folder) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFolder); ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); var folderAccess = folder.Access; @@ -430,7 +429,7 @@ namespace ASC.Web.Files.Services.WCFService if (folder.RootFolderType == FolderType.USER && !Equals(folder.RootFolderCreator, AuthContext.CurrentAccount.ID) - && !FileSecurity.CanRead(folderDao.GetFolder(folder.ParentFolderID))) + && !FileSecurity.CanRead(folderDao.GetFolder(folder.ParentFolderID))) { folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -438,24 +437,24 @@ namespace ASC.Web.Files.Services.WCFService return folder; } - public File GetFile(T fileId, int version) + public File GetFile(T fileId, int version) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); fileDao.InvalidateCache(fileId); var file = version > 0 ? fileDao.GetFile(fileId, version) : fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); EntryManager.SetFileStatus(file); if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -464,16 +463,16 @@ namespace ASC.Web.Files.Services.WCFService return file; } - public ItemList> GetSiblingsFile(T fileId, T parentId, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) + public ItemList> GetSiblingsFile(T fileId, T parentId, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy) { var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); var parent = folderDao.GetFolder(parentId == null || parentId.Equals(default) ? file.FolderID : parentId); ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound); @@ -497,9 +496,9 @@ namespace ASC.Web.Files.Services.WCFService orderBy.SortedBy = SortedByType.New; } - var entries = Enumerable.Empty(); + var entries = Enumerable.Empty>(); - if (!FileSecurity.CanRead(parent)) + if (!FileSecurity.CanRead(parent)) { file.FolderID = GlobalFolderHelper.GetFolderShare(); entries = entries.Concat(new[] { file }); @@ -530,17 +529,17 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList>(result); } - public File CreateNewFile(FileModel fileWrapper) + public File CreateNewFile(FileModel fileWrapper) { if (string.IsNullOrEmpty(fileWrapper.Title) || fileWrapper.ParentId == null) throw new ArgumentException(); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); var folder = folderDao.GetFolder(fileWrapper.ParentId); ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound); ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_CreateNewFolderInTrash); - ErrorIf(!FileSecurity.CanCreate(folder), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(folder), FilesCommonResource.ErrorMassage_SecurityException_Create); var file = ServiceProvider.GetService>(); file.FolderID = folder.ID; @@ -580,17 +579,17 @@ namespace ASC.Web.Files.Services.WCFService } FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileCreated, file.Title); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); return file; } - public KeyValuePair TrackEditFile(string fileId, Guid tabId, string docKeyForTrack, string doc = null, bool isFinish = false) + public KeyValuePair TrackEditFile(T fileId, Guid tabId, string docKeyForTrack, string doc = null, bool isFinish = false) { try { - var id = FileShareLink.Parse(doc); - if (string.IsNullOrEmpty(id)) + var id = FileShareLink.Parse(doc); + if (id == null) { if (!AuthContext.IsAuthenticated) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); if (!string.IsNullOrEmpty(doc)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); @@ -617,17 +616,17 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemDictionary CheckEditing(ItemList filesId) + public ItemDictionary CheckEditing(ItemList filesId) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); var result = new ItemDictionary(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var ids = filesId.Where(FileTracker.IsEditing).Select(id => id).ToArray(); foreach (var file in fileDao.GetFiles(ids)) { - if (file == null || !FileSecurity.CanEdit(file) && !FileSecurity.CanReview(file)) continue; + if (file == null || !FileSecurity.CanEdit(file) && !FileSecurity.CanReview(file)) continue; var usersId = FileTracker.GetEditingBy(file.ID); var value = string.Join(", ", usersId.Select(userId => Global.GetUserName(userId, true)).ToArray()); @@ -637,7 +636,7 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public File SaveEditing(T fileId, string fileExtension, string fileuri, Stream stream, string doc = null, bool forcesave = false) + public File SaveEditing(T fileId, string fileExtension, string fileuri, Stream stream, string doc = null, bool forcesave = false) { try { @@ -660,7 +659,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public File UpdateFileStream(T fileId, Stream stream, bool encrypted) + public File UpdateFileStream(T fileId, Stream stream, bool encrypted) { try { @@ -683,7 +682,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public string StartEdit(T fileId, bool editingAlone = false, string doc = null) + public string StartEdit(T fileId, bool editingAlone = false, string doc = null) { try { @@ -712,7 +711,7 @@ namespace ASC.Web.Files.Services.WCFService else { var file = app.GetFile(fileId.ToString(), out var editable); - DocumentServiceHelper.GetParams(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false, out configuration); + DocumentServiceHelper.GetParams(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false, out configuration); } ErrorIf(!configuration.EditorConfig.ModeWrite @@ -737,7 +736,7 @@ namespace ASC.Web.Files.Services.WCFService } } - public File FileRename(T fileId, string title) + public File FileRename(T fileId, string title) { try { @@ -755,8 +754,8 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -770,16 +769,16 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList> GetFileHistory(T fileId) + public ItemList> GetFileHistory(T fileId) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId); - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); return new ItemList>(fileDao.GetFileHistory(fileId)); } - public KeyValuePair>> UpdateToVersion(T fileId, int version) + public KeyValuePair, ItemList>> UpdateToVersion(T fileId, int version) { var file = EntryManager.UpdateToVersionFile(fileId, version); FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture)); @@ -787,22 +786,22 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } - return new KeyValuePair>>(file, GetFileHistory(fileId)); + return new KeyValuePair, ItemList>>(file, GetFileHistory(fileId)); } - public string UpdateComment(T fileId, int version, string comment) + public string UpdateComment(T fileId, int version, string comment) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId, version); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanEdit(file) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); + ErrorIf(!FileSecurity.CanEdit(file) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile); ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -813,7 +812,7 @@ namespace ASC.Web.Files.Services.WCFService return comment; } - public KeyValuePair>> CompleteVersion(T fileId, int version, bool continueVersion) + public KeyValuePair, ItemList>> CompleteVersion(T fileId, int version, bool continueVersion) { var file = EntryManager.CompleteVersionFile(fileId, version, continueVersion); @@ -824,24 +823,24 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } - return new KeyValuePair>>(file, GetFileHistory(fileId)); + return new KeyValuePair, ItemList>>(file, GetFileHistory(fileId)); } - public File LockFile(T fileId, bool lockfile) + public File LockFile(T fileId, bool lockfile) { var tagDao = GetTagDao(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!FileSecurity.CanEdit(file) || lockfile && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); + ErrorIf(!FileSecurity.CanEdit(file) || lockfile && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager), FilesCommonResource.ErrorMassage_SecurityException_EditFile); ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem); var tagLocked = tagDao.GetTags(file.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); @@ -882,7 +881,7 @@ namespace ASC.Web.Files.Services.WCFService if (!file.ProviderEntry) { file = EntryManager.CompleteVersionFile(file.ID, 0, false); - UpdateComment(file.ID.ToString(), file.Version, FilesCommonResource.UnlockComment); + UpdateComment(file.ID, file.Version, FilesCommonResource.UnlockComment); } } @@ -891,8 +890,8 @@ namespace ASC.Web.Files.Services.WCFService if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) { - var folderDao = GetFolderDao(); - if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) + var folderDao = GetFolderDao(); + if (!FileSecurity.CanRead(folderDao.GetFolder(file.FolderID))) { file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } @@ -901,23 +900,23 @@ namespace ASC.Web.Files.Services.WCFService return file; } - public ItemList GetEditHistory(T fileId, string doc = null) + public ItemList GetEditHistory(T fileId, string doc = null) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var readLink = FileShareLink.Check(doc, true, fileDao, out var file); if (file == null) file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest); return new ItemList(fileDao.GetEditHistory(DocumentServiceHelper, file.ID)); } - public EditHistoryData GetEditDiffUrl(T fileId, int version = 0, string doc = null) + public EditHistoryData GetEditDiffUrl(T fileId, int version = 0, string doc = null) { - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var readLink = FileShareLink.Check(doc, true, fileDao, out var file); if (file != null) @@ -934,7 +933,7 @@ namespace ASC.Web.Files.Services.WCFService } ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); - ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest); var result = new EditHistoryData @@ -991,7 +990,7 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList RestoreVersion(T fileId, int version, string url = null, string doc = null) + public ItemList RestoreVersion(T fileId, int version, string url = null, string doc = null) { IFileDao fileDao; File file; @@ -1002,7 +1001,7 @@ namespace ASC.Web.Files.Services.WCFService else { string modifiedOnString; - fileDao = GetFileDao(); + fileDao = GetFileDao(); var fromFile = fileDao.GetFile(fileId, version); modifiedOnString = fromFile.ModifiedOnString; file = EntryManager.SaveEditing(fileId, null, url, null, doc, string.Format(FilesCommonResource.CommentRevertChanges, modifiedOnString)); @@ -1010,11 +1009,11 @@ namespace ASC.Web.Files.Services.WCFService FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture)); - fileDao = GetFileDao(); + fileDao = GetFileDao(); return new ItemList(fileDao.GetEditHistory(DocumentServiceHelper, file.ID)); } - public Web.Core.Files.DocumentService.FileLink GetPresignedUri(string fileId) + public Web.Core.Files.DocumentService.FileLink GetPresignedUri(T fileId) { var file = GetFile(fileId, -1); var result = new Web.Core.Files.DocumentService.FileLink @@ -1028,26 +1027,26 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public object GetNewItems(T folderId) + public object GetNewItems(T folderId) { try { Folder folder; - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); folder = folderDao.GetFolder(folderId); var result = FileMarker.MarkedItems(folder); - result = new List(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false))); + result = new List>(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false))); if (!result.ToList().Any()) { - MarkAsRead(new ItemList { "folder_" + folderId }); + MarkAsRead(new ItemList { "folder_" + folderId }); } var response = new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StreamContent(serializer.ToXml(new ItemList(result))) + Content = new StreamContent(serializer.ToXml(new ItemList>(result))) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return response; @@ -1058,11 +1057,11 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList MarkAsRead(ItemList items) + public ItemList MarkAsRead(ItemList items) { if (items.Count == 0) return GetTasksStatuses(); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return FileOperationsManagerHelper.MarkAsRead(foldersId, filesId); } @@ -1087,7 +1086,7 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(resultList.ToList()); } - public ItemList> GetThirdPartyFolder(int folderType = 0) + public ItemList> GetThirdPartyFolder(int folderType = 0) { var providerDao = GetProviderDao(); if (providerDao == null) return new ItemList>(); @@ -1104,16 +1103,16 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList>(folders); } - public Folder SaveThirdParty(ThirdPartyParams thirdPartyParams) + public Folder SaveThirdParty(ThirdPartyParams thirdPartyParams) { - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var providerDao = GetProviderDao(); if (providerDao == null) return null; ErrorIf(thirdPartyParams == null, FilesCommonResource.ErrorMassage_BadRequest); - var parentFolder = folderDao.GetFolder(thirdPartyParams.Corporate && !CoreBaseSettings.Personal ? GlobalFolderHelper.FolderCommon : GlobalFolderHelper.FolderMy); - ErrorIf(!FileSecurity.CanCreate(parentFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); + var parentFolder = folderDao.GetFolder(thirdPartyParams.Corporate && !CoreBaseSettings.Personal ? GlobalFolderHelper.GetFolderCommon() : GlobalFolderHelper.GetFolderMy()); + ErrorIf(!FileSecurity.CanCreate(parentFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); ErrorIf(!Global.IsAdministrator && !FilesSettingsHelper.EnableThirdParty, FilesCommonResource.ErrorMassage_SecurityException_Create); var lostFolderType = FolderType.USER; @@ -1169,21 +1168,21 @@ namespace ASC.Web.Files.Services.WCFService var provider = providerDao.GetProviderInfo(curProviderId); provider.InvalidateStorage(); - var folderDao1 = GetFolderDao(); + var folderDao1 = GetFolderDao(); var folder = folderDao1.GetFolder((T)Convert.ChangeType(provider.RootFolderId, typeof(T))); - ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); FilesMessageService.Send(parentFolder, GetHttpHeaders(), messageAction, folder.ID.ToString(), provider.ProviderKey); if (thirdPartyParams.Corporate && lostFolderType != FolderType.COMMON) { - FileMarker.MarkAsNew(folder); + FileMarker.MarkAsNew(folder); } return folder; } - public object DeleteThirdParty(string providerId) + public object DeleteThirdParty(string providerId) { var providerDao = GetProviderDao(); if (providerDao == null) return null; @@ -1192,7 +1191,7 @@ namespace ASC.Web.Files.Services.WCFService var providerInfo = providerDao.GetProviderInfo(curProviderId); var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo); - ErrorIf(!FileSecurity.CanDelete(folder), FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder); + ErrorIf(!FileSecurity.CanDelete(folder), FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder); if (providerInfo.RootFolderType == FolderType.COMMON) { @@ -1234,7 +1233,7 @@ namespace ASC.Web.Files.Services.WCFService return null; } - public string SendDocuSign(T fileId, DocuSignData docuSignData) + public string SendDocuSign(T fileId, DocuSignData docuSignData) { try { @@ -1271,24 +1270,24 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Download(folders, files, GetHttpHeaders()); } - public ItemDictionary MoveOrCopyFilesCheck(ItemList items, T destFolderId) + public ItemDictionary MoveOrCopyFilesCheck(ItemList items, T destFolderId) { if (items.Count == 0) return new ItemDictionary(); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return new ItemDictionary(MoveOrCopyFilesCheck(filesId, foldersId, destFolderId)); } - private Dictionary MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, T destFolderId) + private Dictionary MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, T destFolderId) { var result = new Dictionary(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var toFolder = folderDao.GetFolder(destFolderId); ErrorIf(toFolder == null, FilesCommonResource.ErrorMassage_FolderNotFound); - ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); + ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); foreach (var id in filesId) { @@ -1334,12 +1333,12 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList MoveOrCopyItems(ItemList items, T destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) + public ItemList MoveOrCopyItems(ItemList items, T destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) { ItemList result; if (items.Count != 0) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); } @@ -1350,17 +1349,17 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList DeleteItems(string action, ItemList items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) + public ItemList DeleteItems(string action, ItemList items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) { - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); return FileOperationsManagerHelper.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); } - public ItemList EmptyTrash() + public ItemList EmptyTrash() { - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); var trashId = folderDao.GetFolderIDTrash(true); var foldersId = folderDao.GetFolders(trashId).Select(f => f.ID).ToList(); var filesId = fileDao.GetFiles(trashId).ToList(); @@ -1368,11 +1367,11 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Delete(foldersId, filesId, false, true, false, GetHttpHeaders()); } - public ItemList CheckConversion(ItemList> filesInfoJSON) + public ItemList CheckConversion(ItemList> filesInfoJSON) { if (filesInfoJSON == null || filesInfoJSON.Count == 0) return new ItemList(); - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var files = new List, bool>>(); foreach (var fileInfo in filesInfoJSON) { @@ -1392,7 +1391,7 @@ namespace ASC.Web.Files.Services.WCFService continue; } - ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); var startConvert = Convert.ToBoolean(fileInfo[2]); if (startConvert && FileConverter.MustConvert(file)) @@ -1415,7 +1414,7 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(results); } - public void ReassignStorage(Guid userFromId, Guid userToId) + public void ReassignStorage(Guid userFromId, Guid userToId) { //check current user have access ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException); @@ -1443,8 +1442,8 @@ namespace ASC.Web.Files.Services.WCFService } } - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); if (!userFrom.IsVisitor(UserManager)) { @@ -1470,7 +1469,7 @@ namespace ASC.Web.Files.Services.WCFService EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userFrom.ID, userTo.ID, folderDao, fileDao); } - public void DeleteStorage(Guid userId) + public void DeleteStorage(Guid userId) { //check current user have access ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException); @@ -1491,8 +1490,8 @@ namespace ASC.Web.Files.Services.WCFService } } - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); //delete all markAsNew var rootFoldersId = new List @@ -1536,20 +1535,20 @@ namespace ASC.Web.Files.Services.WCFService EntryManager.ReassignItems(GlobalFolderHelper.GetFolderCommon(), userId, AuthContext.CurrentAccount.ID, folderDao, fileDao); } - public ItemList GetSharedInfo(ItemList objectIds) + public ItemList GetSharedInfo(ItemList objectIds) { return FileSharing.GetSharedInfo(objectIds); } - public ItemList GetSharedInfoShort(string objectId) + public ItemList GetSharedInfoShort(string objectId) { return FileSharing.GetSharedInfoShort(objectId); } - public ItemList SetAceObject(AceCollection aceCollection, bool notify) + public ItemList SetAceObject(AceCollection aceCollection, bool notify) { - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); var result = new ItemList(); foreach (var objectId in aceCollection.Entries) { @@ -1557,12 +1556,12 @@ namespace ASC.Web.Files.Services.WCFService var entryType = objectId.StartsWith("file_") ? FileEntryType.File : FileEntryType.Folder; var entryId = (T)Convert.ChangeType(objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length), typeof(T)); var entry = entryType == FileEntryType.File - ? (FileEntry)fileDao.GetFile(entryId) - : (FileEntry)folderDao.GetFolder(entryId); + ? fileDao.GetFile(entryId) + : (FileEntry)folderDao.GetFolder(entryId); try { - var changed = FileSharingAceHelper.SetAceObject(aceCollection.Aces, entry, notify, aceCollection.Message); + var changed = FileSharingAceHelper.SetAceObject(aceCollection.Aces, entry, notify, aceCollection.Message); if (changed) { FilesMessageService.Send(entry, GetHttpHeaders(), @@ -1584,27 +1583,27 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public void RemoveAce(ItemList items) + public void RemoveAce(ItemList items) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); - var entries = new List(); + var entries = new List>(); - var fileDao = GetFileDao(); - var folderDao = GetFolderDao(); + var fileDao = GetFileDao(); + var folderDao = GetFolderDao(); entries.AddRange(filesId.Select(fileId => fileDao.GetFile(fileId))); entries.AddRange(foldersId.Select(folderDao.GetFolder)); - FileSharingAceHelper.RemoveAce(entries); + FileSharingAceHelper.RemoveAce(entries); } - public string GetShortenLink(T fileId) + public string GetShortenLink(T fileId) { File file; - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); - ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException); var shareLink = FileShareLink.GetLink(file); try @@ -1617,10 +1616,10 @@ namespace ASC.Web.Files.Services.WCFService } } - public bool SetAceLink(T fileId, FileShare share) + public bool SetAceLink(T fileId, FileShare share) { - FileEntry file; - var fileDao = GetFileDao(); + FileEntry file; + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); var aces = new List { @@ -1635,7 +1634,7 @@ namespace ASC.Web.Files.Services.WCFService try { - var changed = FileSharingAceHelper.SetAceObject(aces, file, false, null); + var changed = FileSharingAceHelper.SetAceObject(aces, file, false, null); if (changed) { FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdatedAccess, file.Title); @@ -1650,21 +1649,21 @@ namespace ASC.Web.Files.Services.WCFService return securityDao.IsShared(file.ID, FileEntryType.File); } - public ItemList SharedUsers(T fileId) + public ItemList SharedUsers(T fileId) { if (!AuthContext.IsAuthenticated || CoreBaseSettings.Personal) return null; - FileEntry file; - var fileDao = GetFileDao(); + FileEntry file; + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); var usersIdWithAccess = new List(); - if (FileSharing.CanSetAccess(file)) + if (FileSharing.CanSetAccess(file)) { - var access = FileSharing.GetSharedInfo(file); + var access = FileSharing.GetSharedInfo(file); usersIdWithAccess = access.Where(aceWrapper => !aceWrapper.SubjectGroup && aceWrapper.Share != FileShare.Restrict) .Select(aceWrapper => aceWrapper.SubjectId) .ToList(); @@ -1688,18 +1687,18 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(users); } - public ItemList SendEditorNotify(T fileId, MentionMessageWrapper mentionMessage) + public ItemList SendEditorNotify(T fileId, MentionMessageWrapper mentionMessage) { ErrorIf(!AuthContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException); File file; - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); file = fileDao.GetFile(fileId); ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - ErrorIf(!fileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + ErrorIf(!fileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile); ErrorIf(mentionMessage == null || mentionMessage.Emails == null, FilesCommonResource.ErrorMassage_BadRequest); var changed = false; @@ -1711,7 +1710,7 @@ namespace ASC.Web.Files.Services.WCFService { if (!canShare.HasValue) { - canShare = FileSharing.CanSetAccess(file); + canShare = FileSharing.CanSetAccess(file); } var recipient = UserManager.GetUserByEmail(email); @@ -1721,7 +1720,7 @@ namespace ASC.Web.Files.Services.WCFService continue; } - if (!fileSecurity.CanRead(file, recipient.ID)) + if (!fileSecurity.CanRead(file, recipient.ID)) { if (!canShare.Value) { @@ -1740,7 +1739,7 @@ namespace ASC.Web.Files.Services.WCFService } }; - changed |= FileSharingAceHelper.SetAceObject(aces, file, false, null); + changed |= FileSharingAceHelper.SetAceObject(aces, file, false, null); recipients.Add(recipient.ID); } @@ -1775,7 +1774,7 @@ namespace ASC.Web.Files.Services.WCFService NotifyClient.SendEditorMentions(file, fileLink, recipients, message); - return changed ? GetSharedInfoShort("file_" + fileId) : null; + return changed ? GetSharedInfoShort("file_" + fileId) : null; } public ItemList GetMailAccounts() @@ -1807,21 +1806,21 @@ namespace ASC.Web.Files.Services.WCFService //return new ItemList(accounts); } - public ItemList ChangeOwner(ItemList items, Guid userId) + public ItemList> ChangeOwner(ItemList items, Guid userId) { var userInfo = UserManager.GetUsers(userId); ErrorIf(Equals(userInfo, Constants.LostUser) || userInfo.IsVisitor(UserManager), FilesCommonResource.ErrorMassage_ChangeOwner); - ParseArrayItems(items, out var foldersId, out var filesId); + ParseArrayItems(items, out var foldersId, out var filesId); - var entries = new List(); + var entries = new List>(); - var folderDao = GetFolderDao(); + var folderDao = GetFolderDao(); var folders = folderDao.GetFolders(foldersId.ToArray()); foreach (var folder in folders) { - ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException); ErrorIf(folder.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException); if (folder.ProviderEntry) continue; @@ -1841,12 +1840,12 @@ namespace ASC.Web.Files.Services.WCFService entries.Add(newFolder); } - var fileDao = GetFileDao(); + var fileDao = GetFileDao(); var files = fileDao.GetFiles(filesId.ToArray()); foreach (var file in files) { - ErrorIf(!FileSecurity.CanEdit(file), FilesCommonResource.ErrorMassage_SecurityException); + ErrorIf(!FileSecurity.CanEdit(file), FilesCommonResource.ErrorMassage_SecurityException); ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile); ErrorIf(FileTracker.IsEditing(file.ID), FilesCommonResource.ErrorMassage_UpdateEditingFile); ErrorIf(file.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException); @@ -1874,7 +1873,7 @@ namespace ASC.Web.Files.Services.WCFService newFile = fileDao.SaveFile(newFile, stream); } - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); EntryManager.SetFileStatus(newFile); @@ -1883,7 +1882,7 @@ namespace ASC.Web.Files.Services.WCFService entries.Add(newFile); } - return new ItemList(entries); + return new ItemList>(entries); } public bool StoreOriginal(bool set) @@ -1946,19 +1945,19 @@ namespace ASC.Web.Files.Services.WCFService return ""; //TODO: Studio.UserControls.Common.HelpCenter.HelpCenter.RenderControlToString(); } - private IFolderDao GetFolderDao() + private IFolderDao GetFolderDao() { return DaoFactory.GetFolderDao(); } - private IFileDao GetFileDao() + private IFileDao GetFileDao() { return DaoFactory.GetFileDao(); } - private ITagDao GetTagDao() + private ITagDao GetTagDao() { - return DaoFactory.TagDao; + return DaoFactory.GetTagDao(); } private IDataStore GetStoreTemplate() @@ -1971,12 +1970,12 @@ namespace ASC.Web.Files.Services.WCFService return DaoFactory.ProviderDao; } - private ISecurityDao GetSecurityDao() + private ISecurityDao GetSecurityDao() { - return DaoFactory.SecurityDao; + return DaoFactory.GetSecurityDao(); } - private static void ParseArrayItems(IEnumerable data, out List foldersId, out List filesId) + private static void ParseArrayItems(IEnumerable data, out List foldersId, out List filesId) { //TODO:!!!!Fix foldersId = new List(); @@ -2037,7 +2036,8 @@ namespace ASC.Web.Files.Services.WCFService { public static DIHelper AddFileStorageService(this DIHelper services) { - services.TryAddScoped(); + services.TryAddScoped>(); + services.TryAddScoped>(); //services.TryAddScoped(); return services .AddGlobalService() diff --git a/products/ASC.Files/Server/Core/Search/FilesWrapper.cs b/products/ASC.Files/Server/Core/Search/FilesWrapper.cs index 901320bd06..33abaea157 100644 --- a/products/ASC.Files/Server/Core/Search/FilesWrapper.cs +++ b/products/ASC.Files/Server/Core/Search/FilesWrapper.cs @@ -38,9 +38,7 @@ using ASC.Files.Core.Data; using ASC.Files.Resources; using ASC.Web.Core.Files; -using Microsoft.Extensions.DependencyInjection; - -using File = ASC.Files.Core.File; +using Microsoft.Extensions.DependencyInjection; namespace ASC.Web.Files.Core.Search { @@ -93,12 +91,12 @@ namespace ASC.Web.Files.Core.Search DaoFactory = daoFactory; } - public static FilesWrapper GetFilesWrapper(IServiceProvider serviceProvider, File d, List parentFolders = null) + public static FilesWrapper GetFilesWrapper(IServiceProvider serviceProvider, File d, List parentFolders = null) { var wrapper = serviceProvider.GetService(); var tenantManager = serviceProvider.GetService(); - wrapper.Id = (int)d.ID; + wrapper.Id = Convert.ToInt32(d.ID); wrapper.Title = d.Title; wrapper.Version = d.Version; wrapper.Encrypted = d.Encrypted; @@ -120,8 +118,8 @@ namespace ASC.Web.Files.Core.Search if (Encrypted) return null; if (!FileUtility.CanIndex(Title)) return null; - var fileDao = DaoFactory.FileDao; - var file = ServiceProvider.GetService(); + var fileDao = DaoFactory.GetFileDao(); + var file = ServiceProvider.GetService>(); file.ID = Id; file.Title = Title; file.Version = Version; diff --git a/products/ASC.Files/Server/Core/Search/FoldersWrapper.cs b/products/ASC.Files/Server/Core/Search/FoldersWrapper.cs index 0ee067115c..5535c718bd 100644 --- a/products/ASC.Files/Server/Core/Search/FoldersWrapper.cs +++ b/products/ASC.Files/Server/Core/Search/FoldersWrapper.cs @@ -45,13 +45,13 @@ namespace ASC.Web.Files.Core.Search protected override string Table { get { return "files_folder"; } } - public static FoldersWrapper GetFolderWrapper(IServiceProvider serviceProvider, Folder d) + public static FoldersWrapper GetFolderWrapper(IServiceProvider serviceProvider, Folder d) { var tenantManager = serviceProvider.GetService(); return new FoldersWrapper { - Id = (int)d.ID, + Id = Convert.ToInt32(d.ID), Title = d.Title, TenantId = tenantManager.GetCurrentTenant().TenantId }; diff --git a/products/ASC.Files/Server/Core/Security/FileSecurity.cs b/products/ASC.Files/Server/Core/Security/FileSecurity.cs index 5174c14477..d32e849e74 100644 --- a/products/ASC.Files/Server/Core/Security/FileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/FileSecurity.cs @@ -101,87 +101,87 @@ namespace ASC.Files.Core.Security FileSecurityCommon = fileSecurityCommon; } - public List> CanRead(IEnumerable entry, Guid userId) + public List, bool>> CanRead(IEnumerable> entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Read); + return Can(entry, userId, FilesSecurityActions.Read); } - public bool CanRead(FileEntry entry, Guid userId) + public bool CanRead(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Read); + return Can(entry, userId, FilesSecurityActions.Read); } - public bool CanComment(FileEntry entry, Guid userId) + public bool CanComment(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Comment); + return Can(entry, userId, FilesSecurityActions.Comment); } - public bool CanFillForms(FileEntry entry, Guid userId) + public bool CanFillForms(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.FillForms); + return Can(entry, userId, FilesSecurityActions.FillForms); } - public bool CanReview(FileEntry entry, Guid userId) + public bool CanReview(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Review); + return Can(entry, userId, FilesSecurityActions.Review); } - public bool CanCreate(FileEntry entry, Guid userId) + public bool CanCreate(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Create); + return Can(entry, userId, FilesSecurityActions.Create); } - public bool CanEdit(FileEntry entry, Guid userId) + public bool CanEdit(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Edit); + return Can(entry, userId, FilesSecurityActions.Edit); } - public bool CanDelete(FileEntry entry, Guid userId) + public bool CanDelete(FileEntry entry, Guid userId) { - return Can(entry, userId, FilesSecurityActions.Delete); + return Can(entry, userId, FilesSecurityActions.Delete); } - public bool CanRead(FileEntry entry) + public bool CanRead(FileEntry entry) { - return CanRead(entry, AuthContext.CurrentAccount.ID); + return CanRead(entry, AuthContext.CurrentAccount.ID); } - public bool CanComment(FileEntry entry) + public bool CanComment(FileEntry entry) { - return CanComment(entry, AuthContext.CurrentAccount.ID); + return CanComment(entry, AuthContext.CurrentAccount.ID); } - public bool CanFillForms(FileEntry entry) + public bool CanFillForms(FileEntry entry) { - return CanFillForms(entry, AuthContext.CurrentAccount.ID); + return CanFillForms(entry, AuthContext.CurrentAccount.ID); } - public bool CanReview(FileEntry entry) + public bool CanReview(FileEntry entry) { - return CanReview(entry, AuthContext.CurrentAccount.ID); + return CanReview(entry, AuthContext.CurrentAccount.ID); } - public bool CanCreate(FileEntry entry) + public bool CanCreate(FileEntry entry) { - return CanCreate(entry, AuthContext.CurrentAccount.ID); + return CanCreate(entry, AuthContext.CurrentAccount.ID); } - public bool CanEdit(FileEntry entry) + public bool CanEdit(FileEntry entry) { - return CanEdit(entry, AuthContext.CurrentAccount.ID); + return CanEdit(entry, AuthContext.CurrentAccount.ID); } - public bool CanDelete(FileEntry entry) + public bool CanDelete(FileEntry entry) { - return CanDelete(entry, AuthContext.CurrentAccount.ID); + return CanDelete(entry, AuthContext.CurrentAccount.ID); } - public IEnumerable WhoCanRead(FileEntry entry) + public IEnumerable WhoCanRead(FileEntry entry) { - return WhoCan(entry, FilesSecurityActions.Read); + return WhoCan(entry, FilesSecurityActions.Read); } - private IEnumerable WhoCan(FileEntry entry, FilesSecurityActions action) + private IEnumerable WhoCan(FileEntry entry, FilesSecurityActions action) { var shares = GetShares(entry); @@ -236,7 +236,7 @@ namespace ASC.Files.Core.Security case FolderType.BUNCH: if (action == FilesSecurityActions.Read) { - var folderDao = daoFactory.FolderDao; + var folderDao = daoFactory.GetFolderDao(); var root = folderDao.GetFolder(entry.RootFolderId); if (root != null) { @@ -246,7 +246,7 @@ namespace ASC.Files.Core.Security if (adapter != null) { - return adapter.WhoCanRead(entry); + return adapter.WhoCanRead(entry); } } } @@ -276,58 +276,58 @@ namespace ASC.Files.Core.Security return new[] { x.Subject }; }) .Distinct() - .Where(x => Can(entry, x, action)) + .Where(x => Can(entry, x, action)) .ToList(); } public IEnumerable> FilterRead(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); + return Filter(entries.Cast>(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); } public IEnumerable> FilterRead(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); + return Filter(entries.Cast>(), FilesSecurityActions.Read, AuthContext.CurrentAccount.ID).Cast>(); } public IEnumerable> FilterEdit(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); + return Filter(entries.Cast>(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); } public IEnumerable> FilterEdit(IEnumerable> entries) { - return Filter(entries.Cast(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); + return Filter(entries.Cast>(), FilesSecurityActions.Edit, AuthContext.CurrentAccount.ID).Cast>(); } - private bool Can(FileEntry entry, Guid userId, FilesSecurityActions action) + private bool Can(FileEntry entry, Guid userId, FilesSecurityActions action) { - return Filter(new[] { entry }, action, userId).Any(); + return Filter(new[] { entry }, action, userId).Any(); } - private List> Can(IEnumerable entry, Guid userId, FilesSecurityActions action) + private List, bool>> Can(IEnumerable> entry, Guid userId, FilesSecurityActions action) { - var filtres = Filter(entry, action, userId); - return entry.Select(r => new Tuple(r, filtres.Any(a => a.ID.Equals(r.ID)))).ToList(); + var filtres = Filter(entry, action, userId); + return entry.Select(r => new Tuple, bool>(r, filtres.Any(a => a.ID.Equals(r.ID)))).ToList(); } - private IEnumerable Filter(IEnumerable entries, FilesSecurityActions action, Guid userId) + private IEnumerable> Filter(IEnumerable> entries, FilesSecurityActions action, Guid userId) { - if (entries == null || !entries.Any()) return Enumerable.Empty(); + if (entries == null || !entries.Any()) return Enumerable.Empty>(); var user = UserManager.GetUsers(userId); var isOutsider = user.IsOutsider(UserManager); - if (isOutsider && action != FilesSecurityActions.Read) return Enumerable.Empty(); + if (isOutsider && action != FilesSecurityActions.Read) return Enumerable.Empty>(); entries = entries.Where(f => f != null).ToList(); - var result = new List(entries.Count()); + var result = new List>(entries.Count()); // save entries order - var order = entries.Select((f, i) => new { Id = GetUniqID(f), Pos = i }).ToDictionary(e => e.Id, e => e.Pos); + var order = entries.Select((f, i) => new { Id = f.UniqID, Pos = i }).ToDictionary(e => e.Id, e => e.Pos); // common or my files - Func filter = + Func, bool> filter = f => f.RootFolderType == FolderType.COMMON || f.RootFolderType == FolderType.USER || f.RootFolderType == FolderType.SHARE || @@ -353,13 +353,13 @@ namespace ASC.Files.Core.Security continue; } - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((Folder)e).FolderType == FolderType.Projects) + if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((Folder)e).FolderType == FolderType.Projects) { // Root Projects folder read-only continue; } - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((Folder)e).FolderType == FolderType.SHARE) + if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((Folder)e).FolderType == FolderType.SHARE) { // Root Share folder read-only continue; @@ -378,7 +378,7 @@ namespace ASC.Files.Core.Security } if (DefaultCommonShare == FileShare.Read && action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((Folder)e).FolderType == FolderType.COMMON) + ((Folder)e).FolderType == FolderType.COMMON) { // all can read Common folder result.Add(e); @@ -386,7 +386,7 @@ namespace ASC.Files.Core.Security } if (action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((Folder)e).FolderType == FolderType.SHARE) + ((Folder)e).FolderType == FolderType.SHARE) { // all can read Share folder result.Add(e); @@ -416,7 +416,7 @@ namespace ASC.Files.Core.Security if (ace == null) { // share on parent folders - ace = shares.Where(r => Equals(r.EntryId, ((File)e).FolderID) && r.EntryType == FileEntryType.Folder) + ace = shares.Where(r => Equals(r.EntryId, ((File)e).FolderID) && r.EntryType == FileEntryType.Folder) .OrderBy(r => r, new SubjectComparer(subjects)) .ThenBy(r => r.Level) .ThenByDescending(r => r.Share, new FileShareRecord.ShareComparer()) @@ -440,7 +440,7 @@ namespace ASC.Files.Core.Security else if (action == FilesSecurityActions.Review && (e.Access == FileShare.Review || e.Access == FileShare.ReadWrite)) result.Add(e); else if (action == FilesSecurityActions.Edit && e.Access == FileShare.ReadWrite) result.Add(e); else if (action == FilesSecurityActions.Create && e.Access == FileShare.ReadWrite) result.Add(e); - else if (e.Access != FileShare.Restrict && e.CreateBy == userId && (e.FileEntryType == FileEntryType.File || ((Folder)e).FolderType != FolderType.COMMON)) result.Add(e); + else if (e.Access != FileShare.Restrict && e.CreateBy == userId && (e.FileEntryType == FileEntryType.File || ((Folder)e).FolderType != FolderType.COMMON)) result.Add(e); if (e.CreateBy == userId) e.Access = FileShare.None; //HACK: for client } @@ -450,7 +450,7 @@ namespace ASC.Files.Core.Security filter = f => f.RootFolderType == FolderType.BUNCH; if (entries.Any(filter)) { - var folderDao = daoFactory.FolderDao; + var folderDao = daoFactory.GetFolderDao(); var filteredEntries = entries.Where(filter).ToList(); var roots = filteredEntries .Select(r => r.RootFolderId) @@ -466,51 +466,51 @@ namespace ASC.Files.Core.Security if (adapter == null) continue; - if (adapter.CanRead(e, userId) && - adapter.CanCreate(e, userId) && - adapter.CanEdit(e, userId) && - adapter.CanDelete(e, userId)) + if (adapter.CanRead(e, userId) && + adapter.CanCreate(e, userId) && + adapter.CanEdit(e, userId) && + adapter.CanDelete(e, userId)) { e.Access = FileShare.None; result.Add(e); } - else if (action == FilesSecurityActions.Comment && adapter.CanComment(e, userId)) + else if (action == FilesSecurityActions.Comment && adapter.CanComment(e, userId)) { e.Access = FileShare.Comment; result.Add(e); } - else if (action == FilesSecurityActions.FillForms && adapter.CanFillForms(e, userId)) + else if (action == FilesSecurityActions.FillForms && adapter.CanFillForms(e, userId)) { e.Access = FileShare.FillForms; result.Add(e); } - else if (action == FilesSecurityActions.Review && adapter.CanReview(e, userId)) + else if (action == FilesSecurityActions.Review && adapter.CanReview(e, userId)) { e.Access = FileShare.Review; result.Add(e); } - else if (action == FilesSecurityActions.Create && adapter.CanCreate(e, userId)) + else if (action == FilesSecurityActions.Create && adapter.CanCreate(e, userId)) { e.Access = FileShare.ReadWrite; result.Add(e); } - else if (action == FilesSecurityActions.Delete && adapter.CanDelete(e, userId)) + else if (action == FilesSecurityActions.Delete && adapter.CanDelete(e, userId)) { e.Access = FileShare.ReadWrite; result.Add(e); } - else if (action == FilesSecurityActions.Read && adapter.CanRead(e, userId)) + else if (action == FilesSecurityActions.Read && adapter.CanRead(e, userId)) { - if (adapter.CanCreate(e, userId) || - adapter.CanDelete(e, userId) || - adapter.CanEdit(e, userId)) + if (adapter.CanCreate(e, userId) || + adapter.CanDelete(e, userId) || + adapter.CanEdit(e, userId)) e.Access = FileShare.ReadWrite; else e.Access = FileShare.Read; result.Add(e); } - else if (action == FilesSecurityActions.Edit && adapter.CanEdit(e, userId)) + else if (action == FilesSecurityActions.Edit && adapter.CanEdit(e, userId)) { e.Access = FileShare.ReadWrite; @@ -523,7 +523,7 @@ namespace ASC.Files.Core.Security filter = f => f.RootFolderType == FolderType.TRASH; if ((action == FilesSecurityActions.Read || action == FilesSecurityActions.Delete) && entries.Any(filter)) { - var folderDao = daoFactory.FolderDao; + var folderDao = daoFactory.GetFolderDao(); var mytrashId = folderDao.GetFolderIDTrash(false, userId); if (!Equals(mytrashId, 0)) { @@ -539,19 +539,13 @@ namespace ASC.Files.Core.Security } // restore entries order - result.Sort((x, y) => order[GetUniqID(x)].CompareTo(order[GetUniqID(y)])); + result.Sort((x, y) => order[x.UniqID].CompareTo(order[y.UniqID])); return result; - - //TODO - string GetUniqID(FileEntry f) - { - return (f as File)?.UniqID ?? (f as Folder)?.UniqID; - }; } - public void Share(object entryId, FileEntryType entryType, Guid @for, FileShare share) + public void Share(T entryId, FileEntryType entryType, Guid @for, FileShare share) { - var securityDao = daoFactory.SecurityDao; + var securityDao = daoFactory.GetSecurityDao(); var r = new FileShareRecord { Tenant = TenantManager.GetCurrentTenant().TenantId, @@ -564,21 +558,21 @@ namespace ASC.Files.Core.Security securityDao.SetShare(r); } - public IEnumerable GetShares(IEnumerable entries) + public IEnumerable GetShares(IEnumerable> entries) { - return daoFactory.SecurityDao.GetShares(entries); + return daoFactory.GetSecurityDao().GetShares(entries); } - public IEnumerable GetShares(FileEntry entry) + public IEnumerable GetShares(FileEntry entry) { - return daoFactory.SecurityDao.GetShares(entry); + return daoFactory.GetSecurityDao().GetShares(entry); } - public List GetSharesForMe(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false) + public List> GetSharesForMe(FilterType filterType, bool subjectGroup, Guid subjectID, string searchText = "", bool searchInContent = false, bool withSubfolders = false) { var folderDao = daoFactory.GetFolderDao(); var fileDao = daoFactory.GetFileDao(); - var securityDao = daoFactory.SecurityDao; + var securityDao = daoFactory.GetSecurityDao(); var subjects = GetUserSubjects(AuthContext.CurrentAccount.ID); var records = securityDao.GetShares(subjects); @@ -607,7 +601,7 @@ namespace ASC.Files.Core.Security } } - var entries = new List(); + var entries = new List>(); if (filterType != FilterType.FoldersOnly) { @@ -642,7 +636,7 @@ namespace ASC.Files.Core.Security } }); - entries.AddRange(folders.Cast()); + entries.AddRange(folders.Cast>()); } if (filterType != FilterType.FoldersOnly && withSubfolders) @@ -685,9 +679,9 @@ namespace ASC.Files.Core.Security return entries.Where(x => string.IsNullOrEmpty(x.Error)).ToList(); } - public void RemoveSubject(Guid subject) + public void RemoveSubject(Guid subject) { - daoFactory.SecurityDao.RemoveSubject(subject); + daoFactory.GetSecurityDao().RemoveSubject(subject); } public List GetUserSubjects(Guid userId) diff --git a/products/ASC.Files/Server/Core/Security/IFileSecurity.cs b/products/ASC.Files/Server/Core/Security/IFileSecurity.cs index 594f0dddc1..f2814756a6 100644 --- a/products/ASC.Files/Server/Core/Security/IFileSecurity.cs +++ b/products/ASC.Files/Server/Core/Security/IFileSecurity.cs @@ -31,20 +31,20 @@ namespace ASC.Files.Core.Security { public interface IFileSecurity { - bool CanRead(FileEntry entry, Guid userId); + bool CanRead(FileEntry entry, Guid userId); - bool CanComment(FileEntry entry, Guid userId); + bool CanComment(FileEntry entry, Guid userId); - bool CanReview(FileEntry entry, Guid userId); + bool CanReview(FileEntry entry, Guid userId); - bool CanFillForms(FileEntry entry, Guid userId); + bool CanFillForms(FileEntry entry, Guid userId); - bool CanCreate(FileEntry entry, Guid userId); + bool CanCreate(FileEntry entry, Guid userId); - bool CanEdit(FileEntry entry, Guid userId); + bool CanEdit(FileEntry entry, Guid userId); - bool CanDelete(FileEntry entry, Guid userId); + bool CanDelete(FileEntry entry, Guid userId); - IEnumerable WhoCanRead(FileEntry entry); + IEnumerable WhoCanRead(FileEntry entry); } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Security/ISecurityDao.cs b/products/ASC.Files/Server/Core/Security/ISecurityDao.cs index 59cb798a49..484f07f059 100644 --- a/products/ASC.Files/Server/Core/Security/ISecurityDao.cs +++ b/products/ASC.Files/Server/Core/Security/ISecurityDao.cs @@ -29,21 +29,21 @@ using System.Collections.Generic; namespace ASC.Files.Core.Security { - public interface ISecurityDao + public interface ISecurityDao { void SetShare(FileShareRecord r); IEnumerable GetShares(IEnumerable subjects); - IEnumerable GetShares(IEnumerable entry); + IEnumerable GetShares(IEnumerable> entry); - IEnumerable GetShares(FileEntry entry); + IEnumerable GetShares(FileEntry entry); void RemoveSubject(Guid subject); - IEnumerable GetPureShareRecords(IEnumerable entries); + IEnumerable GetPureShareRecords(IEnumerable> entries); - IEnumerable GetPureShareRecords(FileEntry entry); + IEnumerable GetPureShareRecords(FileEntry entry); void DeleteShareRecords(IEnumerable records); diff --git a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs index 57e6d2d30d..15c05e1800 100644 --- a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs +++ b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs @@ -254,7 +254,7 @@ namespace ASC.Web.Files.Helpers var fileDao = DaoFactory.GetFileDao(); file = fileDao.GetFile(fileId); if (file == null) throw new Exception(FilesCommonResource.ErrorMassage_FileNotFound); - if (!FileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + if (!FileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); if (!SupportedFormats.Contains(FileUtility.GetFileExtension(file.Title))) throw new ArgumentException(FilesCommonResource.ErrorMassage_NotSupportedFormat); if (file.ContentLength > MaxFileSize) throw new Exception(FileSizeComment.GetFileSizeExceptionString(MaxFileSize)); @@ -393,7 +393,7 @@ namespace ASC.Web.Files.Helpers if (folderId == null || (folder = folderDao.GetFolder(folderId)) == null || folder.RootFolderType == FolderType.TRASH - || !FileSecurity.CanCreate(folder)) + || !FileSecurity.CanCreate(folder)) { if (GlobalFolderHelper.FolderMy != 0) { @@ -420,7 +420,7 @@ namespace ASC.Web.Files.Helpers FilesMessageService.Send(file, MessageInitiator.ThirdPartyProvider, MessageAction.DocumentSignComplete, "DocuSign", file.Title); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); return file; } diff --git a/products/ASC.Files/Server/Helpers/FilesMessageService.cs b/products/ASC.Files/Server/Helpers/FilesMessageService.cs index 6b156a5882..0ca1524848 100644 --- a/products/ASC.Files/Server/Helpers/FilesMessageService.cs +++ b/products/ASC.Files/Server/Helpers/FilesMessageService.cs @@ -69,7 +69,7 @@ namespace ASC.Web.Files.Helpers SendHeadersMessage(headers, action, null); } - public void Send(FileEntry entry, Dictionary headers, MessageAction action, params string[] description) + public void Send(FileEntry entry, Dictionary headers, MessageAction action, params string[] description) { // do not log actions in users folder if (entry == null || entry.RootFolderType == FolderType.USER) return; @@ -77,7 +77,7 @@ namespace ASC.Web.Files.Helpers SendHeadersMessage(headers, action, MessageTarget.Create(entry.ID), description); } - public void Send(FileEntry entry1, FileEntry entry2, Dictionary headers, MessageAction action, params string[] description) + public void Send(FileEntry entry1, FileEntry entry2, Dictionary headers, MessageAction action, params string[] description) { // do not log actions in users folder if (entry1 == null || entry2 == null || entry1.RootFolderType == FolderType.USER || entry2.RootFolderType == FolderType.USER) return; @@ -97,7 +97,7 @@ namespace ASC.Web.Files.Helpers } - public void Send(FileEntry entry, MessageAction action, params string[] description) + public void Send(FileEntry entry, MessageAction action, params string[] description) { // do not log actions in users folder if (entry == null || entry.RootFolderType == FolderType.USER) return; @@ -112,7 +112,7 @@ namespace ASC.Web.Files.Helpers } - public void Send(FileEntry entry, MessageInitiator initiator, MessageAction action, params string[] description) + public void Send(FileEntry entry, MessageInitiator initiator, MessageAction action, params string[] description) { if (entry == null || entry.RootFolderType == FolderType.USER) return; diff --git a/products/ASC.Files/Server/Helpers/Global.cs b/products/ASC.Files/Server/Helpers/Global.cs index ced0b009ac..c85ca571af 100644 --- a/products/ASC.Files/Server/Helpers/Global.cs +++ b/products/ASC.Files/Server/Helpers/Global.cs @@ -381,7 +381,11 @@ namespace ASC.Web.Files.Classes internal static readonly IDictionary TrashFolderCache = new ConcurrentDictionary(); /*Use SYNCHRONIZED for cross thread blocks*/ - public object GetFolderTrash(IFolderDao folderDao) + public T GetFolderTrash(IDaoFactory daoFactory) + { + return (T)Convert.ChangeType(GetFolderTrash(daoFactory), typeof(T)); + } + public object GetFolderTrash(IDaoFactory daoFactory) { if (IsOutsider) return null; @@ -389,7 +393,7 @@ namespace ASC.Web.Files.Classes if (!TrashFolderCache.TryGetValue(cacheKey, out var trashFolderId)) { - trashFolderId = AuthContext.IsAuthenticated ? folderDao.GetFolderIDTrash(true) : 0; + trashFolderId = AuthContext.IsAuthenticated ? daoFactory.GetFolderDao().GetFolderIDTrash(true) : 0; TrashFolderCache[cacheKey] = trashFolderId; } return trashFolderId; @@ -473,7 +477,7 @@ namespace ASC.Web.Files.Classes { file = fileDao.SaveFile(file, stream); - fileMarker.MarkAsNew(file); + fileMarker.MarkAsNew(file); } catch (Exception ex) { @@ -524,7 +528,7 @@ namespace ASC.Web.Files.Classes { get { - return GlobalFolder.GetFolderTrash(DaoFactory.FolderDao); + return GlobalFolder.GetFolderTrash(DaoFactory); } set { diff --git a/products/ASC.Files/Server/Helpers/PathProvider.cs b/products/ASC.Files/Server/Helpers/PathProvider.cs index b3332959cf..86c29d84bc 100644 --- a/products/ASC.Files/Server/Helpers/PathProvider.cs +++ b/products/ASC.Files/Server/Helpers/PathProvider.cs @@ -41,8 +41,6 @@ using ASC.Web.Core.Files; using ASC.Web.Core.Utility.Skins; using ASC.Web.Studio.Utility; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Classes { public class PathProvider @@ -108,11 +106,11 @@ namespace ASC.Web.Files.Classes return BaseCommonLinkUtility.ToAbsolute("~/Products/Files/Controls/" + fileName); } - public string GetFolderUrl(Folder folder, int projectID = 0) + public string GetFolderUrl(Folder folder, int projectID = 0) { if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound); - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); switch (folder.RootFolderType) { @@ -133,14 +131,14 @@ namespace ASC.Web.Files.Classes } } - public string GetFolderUrl(object folderId) + public string GetFolderUrl(T folderId) { - var folder = DaoFactory.FolderDao.GetFolder(folderId); + var folder = DaoFactory.GetFolderDao().GetFolder(folderId); return GetFolderUrl(folder); } - public string GetFileStreamUrl(File file, string doc = null, bool lastVersion = false) + public string GetFileStreamUrl(File file, string doc = null, bool lastVersion = false) { if (file == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); @@ -164,7 +162,7 @@ namespace ASC.Web.Files.Classes return uriBuilder.Uri + "?" + query; } - public string GetFileChangesUrl(File file, string doc = null) + public string GetFileChangesUrl(File file, string doc = null) { if (file == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); diff --git a/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs b/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs index 0d21fd68e1..ccfeace1d7 100644 --- a/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs +++ b/products/ASC.Files/Server/HttpHandlers/ChunkedUploaderHandler.cs @@ -50,8 +50,6 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.HttpHandlers { public class ChunkedUploaderHandler //: AbstractHttpAsyncHandler @@ -206,7 +204,7 @@ namespace ASC.Web.Files.HttpHandlers context.Response.ContentType = "application/json"; } - private static object ToResponseObject(File file) + private static object ToResponseObject(File file) { return new { diff --git a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs index 3217e06bab..f9ecd40a7e 100644 --- a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs @@ -62,7 +62,7 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using File = ASC.Files.Core.File; + using FileShare = ASC.Files.Core.Security.FileShare; using MimeMapping = ASC.Common.Web.MimeMapping; using SecurityContext = ASC.Core.SecurityContext; @@ -303,7 +303,7 @@ namespace ASC.Web.Files return; } - if (!readLink && !FileSecurity.CanRead(file)) + if (!readLink && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -656,7 +656,7 @@ namespace ASC.Web.Files return; } - if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) + if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -902,7 +902,7 @@ namespace ASC.Web.Files return; } - if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) + if (linkRight == FileShare.Restrict && SecurityContext.IsAuthenticated && !FileSecurity.CanRead(file)) { context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return; @@ -944,7 +944,7 @@ namespace ASC.Web.Files } } - private static string GetEtag(File file) + private static string GetEtag(File file) { return file.ID + ":" + file.Version + ":" + file.Title.GetHashCode() + ":" + file.ContentLength; } @@ -971,9 +971,9 @@ namespace ASC.Web.Files folder = folderDao.GetFolder(folderId); if (folder == null) throw new HttpException((int)HttpStatusCode.NotFound, FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanCreate(folder)) throw new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException_Create); + if (!FileSecurity.CanCreate(folder)) throw new HttpException((int)HttpStatusCode.Forbidden, FilesCommonResource.ErrorMassage_SecurityException_Create); - File file; + File file; var fileUri = context.Request.Query[FilesLinkUtility.FileUri]; var fileTitle = context.Request.Query[FilesLinkUtility.FileTitle]; try @@ -1014,7 +1014,7 @@ namespace ASC.Web.Files : (FilesLinkUtility.GetFileWebEditorUrl(file.ID) + "#message/" + HttpUtility.UrlEncode(string.Format(FilesCommonResource.MessageFileCreated, folder.Title)))); } - private File CreateFileFromTemplate(Folder folder, string fileTitle, string docType) + private File CreateFileFromTemplate(Folder folder, string fileTitle, string docType) { var storeTemplate = GlobalStore.GetStoreTemplate(); @@ -1056,7 +1056,7 @@ namespace ASC.Web.Files return fileDao.SaveFile(file, stream); } - private File CreateFileFromUri(Folder folder, string fileUri, string fileTitle) + private File CreateFileFromUri(Folder folder, string fileUri, string fileTitle) { if (string.IsNullOrEmpty(fileTitle)) fileTitle = Path.GetFileName(HttpUtility.UrlDecode(fileUri)); diff --git a/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs b/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs index 617187ab01..db07c0125f 100644 --- a/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs +++ b/products/ASC.Files/Server/HttpHandlers/SearchHandler.cs @@ -102,7 +102,7 @@ namespace ASC.Web.Files.Configuration { var security = FileSecurity; var fileDao = DaoFactory.GetFileDao(); - return fileDao.Search(text).Where(security.CanRead); + return fileDao.Search(text).Where(security.CanRead); } public IEnumerable> SearchFolders(string text) @@ -110,7 +110,7 @@ namespace ASC.Web.Files.Configuration var security = FileSecurity; IEnumerable> result; var folderDao = DaoFactory.GetFolderDao(); - result = folderDao.Search(text).Where(security.CanRead); + result = folderDao.Search(text).Where(security.CanRead); if (ThirdpartyConfiguration.SupportInclusion && (Global.IsAdministrator || FilesSettingsHelper.EnableThirdParty)) @@ -168,7 +168,7 @@ namespace ASC.Web.Files.Configuration return result.Concat(resultFolder).ToArray(); } - private static string FolderPathBuilder(IEnumerable folders) + private static string FolderPathBuilder(IEnumerable> folders) { var titles = folders.Select(f => f.Title).ToList(); const string separator = " \\ "; diff --git a/products/ASC.Files/Server/Model/FileEntryWrapper.cs b/products/ASC.Files/Server/Model/FileEntryWrapper.cs index 231bbbedc2..08de5e4996 100644 --- a/products/ASC.Files/Server/Model/FileEntryWrapper.cs +++ b/products/ASC.Files/Server/Model/FileEntryWrapper.cs @@ -113,7 +113,7 @@ namespace ASC.Api.Documents /// /// /// - protected FileEntryWrapper(FileEntry entry, EmployeeWraperHelper employeeWraperHelper, ApiDateTimeHelper apiDateTimeHelper) + protected FileEntryWrapper(FileEntry entry, EmployeeWraperHelper employeeWraperHelper, ApiDateTimeHelper apiDateTimeHelper) { Id = entry.ID; Title = entry.Title; @@ -152,7 +152,7 @@ namespace ASC.Api.Documents EmployeeWraperHelper = employeeWraperHelper; } - protected internal T Get(FileEntry entry) where T : FileEntryWrapper, new() + protected internal T Get(FileEntry entry) where T : FileEntryWrapper, new() { return new T { diff --git a/products/ASC.Files/Server/Model/FileWrapper.cs b/products/ASC.Files/Server/Model/FileWrapper.cs index a14143df3d..4e68a8a38f 100644 --- a/products/ASC.Files/Server/Model/FileWrapper.cs +++ b/products/ASC.Files/Server/Model/FileWrapper.cs @@ -185,7 +185,7 @@ namespace ASC.Api.Documents result.RootFolderType = FolderType.SHARE; var folderDao = DaoFactory.GetFolderDao(); var parentFolder = folderDao.GetFolder(file.FolderID); - if (!FileSecurity.CanRead(parentFolder)) + if (!FileSecurity.CanRead(parentFolder)) { result.FolderId = GlobalFolderHelper.FolderShare; } diff --git a/products/ASC.Files/Server/Model/FolderWrapper.cs b/products/ASC.Files/Server/Model/FolderWrapper.cs index fa78a82cd1..288a09768e 100644 --- a/products/ASC.Files/Server/Model/FolderWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderWrapper.cs @@ -127,7 +127,7 @@ namespace ASC.Api.Documents var folderDao = DaoFactory.GetFolderDao(); var parentFolder = folderDao.GetFolder(folder.ParentFolderID); - if (!FileSecurity.CanRead(parentFolder)) + if (!FileSecurity.CanRead(parentFolder)) result.ParentId = GlobalFolderHelper.FolderShare; } diff --git a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs index e3173b19bf..bc1690208e 100644 --- a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs +++ b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs @@ -289,7 +289,7 @@ namespace ASC.Web.Files.Services.DocumentService { if (Type == EditorType.Embedded || Type == EditorType.External - || !FileSharing.CanSetAccess(File)) return null; + || !FileSharing.CanSetAccess(File)) return null; try { @@ -717,9 +717,9 @@ namespace ASC.Web.Files.Services.DocumentService var fileSecurity = FileSecurity; if (_configuration.Document.Info.File.RootFolderType == FolderType.USER && !Equals(_configuration.Document.Info.File.RootFolderId, GlobalFolderHelper.FolderMy) - && !fileSecurity.CanRead(parent)) + && !fileSecurity.CanRead(parent)) { - if (fileSecurity.CanRead(_configuration.Document.Info.File)) + if (fileSecurity.CanRead(_configuration.Document.Info.File)) { return new GobackConfig { diff --git a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs index 6e9dad448c..9f02242f17 100644 --- a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs +++ b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceHelper.cs @@ -45,7 +45,6 @@ using ASC.Web.Studio.Core; using JWT; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; namespace ASC.Web.Files.Services.DocumentService @@ -145,17 +144,17 @@ namespace ASC.Web.Files.Services.DocumentService var fileSecurity = FileSecurity; rightToEdit = rightToEdit && (linkRight == FileShare.ReadWrite - || fileSecurity.CanEdit(file)); + || fileSecurity.CanEdit(file)); if (editPossible && !rightToEdit) { editPossible = false; } - rightToRename = rightToRename && rightToEdit && fileSecurity.CanEdit(file); + rightToRename = rightToRename && rightToEdit && fileSecurity.CanEdit(file); rightToReview = rightToReview && (linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanReview(file)); + || fileSecurity.CanReview(file)); if (reviewPossible && !rightToReview) { reviewPossible = false; @@ -163,7 +162,7 @@ namespace ASC.Web.Files.Services.DocumentService rightToFillForms = rightToFillForms && (linkRight == FileShare.FillForms || linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanFillForms(file)); + || fileSecurity.CanFillForms(file)); if (fillFormsPossible && !rightToFillForms) { fillFormsPossible = false; @@ -171,7 +170,7 @@ namespace ASC.Web.Files.Services.DocumentService rightToComment = rightToComment && (linkRight == FileShare.Comment || linkRight == FileShare.Review || linkRight == FileShare.ReadWrite - || fileSecurity.CanComment(file)); + || fileSecurity.CanComment(file)); if (commentPossible && !rightToComment) { commentPossible = false; @@ -179,7 +178,7 @@ namespace ASC.Web.Files.Services.DocumentService if (linkRight == FileShare.Restrict && !(editPossible || reviewPossible || fillFormsPossible || commentPossible) - && !fileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + && !fileSecurity.CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -299,12 +298,12 @@ namespace ASC.Web.Files.Services.DocumentService } - public string GetDocKey(File file) + public string GetDocKey(File file) { return GetDocKey(file.ID, file.Version, file.ProviderEntry ? file.ModifiedOn : file.CreateOn); } - public string GetDocKey(object fileId, int fileVersion, DateTime modified) + public string GetDocKey(T fileId, int fileVersion, DateTime modified) { var str = string.Format("teamlab_{0}_{1}_{2}_{3}", fileId, @@ -325,10 +324,10 @@ namespace ASC.Web.Files.Services.DocumentService { var fileSecurity = FileSecurity; var sharedLink = - fileSecurity.CanEdit(file, FileConstant.ShareLinkId) - || fileSecurity.CanReview(file, FileConstant.ShareLinkId) - || fileSecurity.CanFillForms(file, FileConstant.ShareLinkId) - || fileSecurity.CanComment(file, FileConstant.ShareLinkId); + fileSecurity.CanEdit(file, FileConstant.ShareLinkId) + || fileSecurity.CanReview(file, FileConstant.ShareLinkId) + || fileSecurity.CanFillForms(file, FileConstant.ShareLinkId) + || fileSecurity.CanComment(file, FileConstant.ShareLinkId); var usersDrop = FileTracker.GetEditingBy(file.ID) .Where(uid => @@ -337,7 +336,7 @@ namespace ASC.Web.Files.Services.DocumentService { return !sharedLink; } - return !fileSecurity.CanEdit(file, uid) && !fileSecurity.CanReview(file, uid) && !fileSecurity.CanFillForms(file, uid) && !fileSecurity.CanComment(file, uid); + return !fileSecurity.CanEdit(file, uid) && !fileSecurity.CanReview(file, uid) && !fileSecurity.CanFillForms(file, uid) && !fileSecurity.CanComment(file, uid); }) .Select(u => u.ToString()).ToArray(); diff --git a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs index 69f23ea766..9c66059f85 100644 --- a/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs +++ b/products/ASC.Files/Server/Services/DocumentService/DocumentServiceTracker.cs @@ -62,7 +62,6 @@ using Microsoft.Extensions.Options; using static ASC.Web.Files.Services.DocumentService.DocumentServiceTracker; using CommandMethod = ASC.Web.Core.Files.DocumentService.CommandMethod; -using File = ASC.Files.Core.File; namespace ASC.Web.Files.Services.DocumentService { @@ -293,7 +292,7 @@ namespace ASC.Web.Files.Services.DocumentService var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { - File fileStable; + File fileStable; fileStable = DaoFactory.GetFileDao().GetFileStable(fileId); docKey = DocumentServiceHelper.GetDocKey(fileStable); @@ -364,7 +363,7 @@ namespace ASC.Web.Files.Services.DocumentService var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app == null) { - File fileStable; + File fileStable; fileStable = DaoFactory.GetFileDao().GetFileStable(fileId); var docKey = DocumentServiceHelper.GetDocKey(fileStable); @@ -396,7 +395,7 @@ namespace ASC.Web.Files.Services.DocumentService } } - File file = null; + File file = null; var saveMessage = "Not saved"; if (string.IsNullOrEmpty(fileData.Url)) @@ -407,7 +406,7 @@ namespace ASC.Web.Files.Services.DocumentService file = EntryManager.CompleteVersionFile(fileId, 0, false, false); - DaoFactory.FileDao.UpdateComment(file.ID, file.Version, string.Join("; ", comments)); + DaoFactory.GetFileDao().UpdateComment(file.ID, file.Version, string.Join("; ", comments)); file = null; Logger.ErrorFormat("DocService save error. Empty url. File id: '{0}'. UserId: {1}. DocKey '{2}'", fileId, userId, fileData.Key); @@ -633,7 +632,7 @@ namespace ASC.Web.Files.Services.DocumentService } } - private void SaveHistory(File file, string changes, string differenceUrl) + private void SaveHistory(File file, string changes, string differenceUrl) { if (file == null) return; if (file.ProviderEntry) return; @@ -641,7 +640,7 @@ namespace ASC.Web.Files.Services.DocumentService try { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); var req = (HttpWebRequest)WebRequest.Create(differenceUrl); // hack. http://ubuntuforums.org/showthread.php?t=1841740 diff --git a/products/ASC.Files/Server/Services/NotifyService/NotifyClient.cs b/products/ASC.Files/Server/Services/NotifyService/NotifyClient.cs index b504c25785..5b0436400f 100644 --- a/products/ASC.Files/Server/Services/NotifyService/NotifyClient.cs +++ b/products/ASC.Files/Server/Services/NotifyService/NotifyClient.cs @@ -52,7 +52,7 @@ namespace ASC.Web.Files.Services.NotifyService ServiceProvider = serviceProvider; } - public void SendDocuSignComplete(File file, string sourceTitle) + public void SendDocuSignComplete(File file, string sourceTitle) { using var scope = ServiceProvider.CreateScope(); var notifySource = scope.ServiceProvider.GetService(); @@ -112,7 +112,7 @@ namespace ASC.Web.Files.Services.NotifyService ); } - public void SendShareNotice(FileEntry fileEntry, Dictionary recipients, string message) + public void SendShareNotice(FileEntry fileEntry, Dictionary recipients, string message) { if (fileEntry == null || recipients.Count == 0) return; @@ -127,12 +127,12 @@ namespace ASC.Web.Files.Services.NotifyService var baseCommonLinkUtility = scope.ServiceProvider.GetService(); var client = WorkContext.NotifyContext.NotifyService.RegisterClient(notifySource, scope); - var folderDao = daoFactory.FolderDao; - if (fileEntry.FileEntryType == FileEntryType.File && folderDao.GetFolder(((File)fileEntry).FolderID) == null) return; + var folderDao = daoFactory.GetFolderDao(); + if (fileEntry.FileEntryType == FileEntryType.File && folderDao.GetFolder(((File)fileEntry).FolderID) == null) return; var url = fileEntry.FileEntryType == FileEntryType.File ? filesLinkUtility.GetFileWebPreviewUrl(fileUtility, fileEntry.Title, fileEntry.ID) - : pathProvider.GetFolderUrl(((Folder)fileEntry)); + : pathProvider.GetFolderUrl(((Folder)fileEntry)); var recipientsProvider = notifySource.GetRecipientsProvider(); @@ -160,7 +160,7 @@ namespace ASC.Web.Files.Services.NotifyService } } - public void SendEditorMentions(FileEntry file, string documentUrl, List recipientIds, string message) + public void SendEditorMentions(FileEntry file, string documentUrl, List recipientIds, string message) { if (file == null || recipientIds.Count == 0) return; diff --git a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs index 2ec9a690ff..83c609b561 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs @@ -43,8 +43,8 @@ namespace ASC.Web.Files.Services.WCFService static FileEntrySerializer() { - serializers[typeof(File)] = new DataContractSerializer(typeof(File)); - serializers[typeof(ItemList)] = new DataContractSerializer(typeof(ItemList)); + serializers[typeof(File<>)] = new DataContractSerializer(typeof(File<>)); + //serializers[typeof(ItemList>)] = new DataContractSerializer(typeof(ItemList>)); serializers[typeof(DataWrapper<>)] = new DataContractSerializer(typeof(DataWrapper<>)); //if (WorkContext.IsMono && !string.IsNullOrEmpty(WorkContext.MonoVersion)) @@ -60,7 +60,7 @@ namespace ASC.Web.Files.Services.WCFService //} } - public System.IO.MemoryStream ToXml(object o) + public System.IO.MemoryStream ToXml(object o) { var result = new System.IO.MemoryStream(); if (o == null) @@ -85,7 +85,7 @@ namespace ASC.Web.Files.Services.WCFService //remove incorrect ns foreach (XmlNode entry in xml.SelectNodes("//entry")) { - var nsattr = entry.Attributes.Cast().FirstOrDefault(a => a.Value == typeof(FileEntry).Name); + var nsattr = entry.Attributes.Cast().FirstOrDefault(a => a.Value == typeof(FileEntry).Name); if (nsattr != null) { foreach (XmlAttribute a in entry.Attributes) @@ -128,7 +128,7 @@ namespace ASC.Web.Files.Services.WCFService typeName = XmlDictionaryString.Empty; typeNamespace = XmlDictionaryString.Empty; - if (declaredType == typeof(FileEntry)) + if (declaredType == typeof(FileEntry<>)) { typeName = new XmlDictionaryString(XmlDictionary.Empty, type.Name.ToLower(), 0); typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, declaredType.Name, 0); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index da12ecde02..2dc4518692 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -81,7 +81,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { _trashId = FolderDao.GetFolderIDTrash(true); - Folder root = null; + Folder root = null; if (0 < Folders.Count) { root = FolderDao.GetRootFolder(Folders[0]); @@ -118,7 +118,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder; } - else if (!_ignoreException && !FilesSecurity.CanDelete(folder)) + else if (!_ignoreException && !FilesSecurity.CanDelete(folder)) { canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId; @@ -229,14 +229,14 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - private bool WithError(IServiceScope scope, IEnumerable files, bool folder, out string error) + private bool WithError(IServiceScope scope, IEnumerable> files, bool folder, out string error) { var entryManager = scope.ServiceProvider.GetService(); error = null; foreach (var file in files) { - if (!FilesSecurity.CanDelete(file)) + if (!FilesSecurity.CanDelete(file)) { error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFile; return true; diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs index 15a82bd0b6..0b359cc704 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs @@ -147,7 +147,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } if (0 < Folders.Count) { - FilesSecurity.FilterRead(FolderDao.GetFolders(Files.ToArray())).ToList().Cast().ToList() + FilesSecurity.FilterRead(FolderDao.GetFolders(Files.ToArray())).ToList().Cast>().ToList() .ForEach(folder => fileMarker.RemoveMarkAsNew(folder)); var filesInFolder = GetFilesInFolders(scope, Folders, string.Empty); @@ -168,7 +168,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations CancellationToken.ThrowIfCancellationRequested(); var folder = FolderDao.GetFolder(folderId); - if (folder == null || !FilesSecurity.CanRead(folder)) continue; + if (folder == null || !FilesSecurity.CanRead(folder)) continue; var folderPath = path + folder.Title + "/"; var files = FileDao.GetFiles(folder.ID, null, FilterType.None, false, Guid.Empty, string.Empty, true); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs index 79b402e651..dd0b82f610 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs @@ -67,7 +67,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected override void Do(IServiceScope scope) { var fileMarker = scope.ServiceProvider.GetService(); - var entries = new List(); + var entries = new List>(); if (Folders.Any()) { entries.AddRange(FolderDao.GetFolders(Folders.ToArray())); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index 8c1bdd87f7..404a9dceab 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -63,7 +63,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations private readonly T _toFolderId; private readonly bool _copy; private readonly FileConflictResolveType _resolveType; - private readonly List _needToMark = new List(); + private readonly List> _needToMark = new List>(); private readonly Dictionary _headers; @@ -91,7 +91,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations //TODO: check on each iteration? var toFolder = FolderDao.GetFolder(_toFolderId); if (toFolder == null) return; - if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); + if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID))) { @@ -101,7 +101,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (_copy) { - Folder rootFrom = null; + Folder rootFrom = null; if (0 < Folders.Count) rootFrom = FolderDao.GetRootFolder(Folders[0]); if (0 < Files.Count) rootFrom = FolderDao.GetRootFolderByFile(Files[0]); if (rootFrom != null && rootFrom.FolderType == FolderType.TRASH) throw new InvalidOperationException("Can not copy from Trash."); @@ -132,7 +132,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_FolderNotFound; } - else if (!FilesSecurity.CanRead(folder)) + else if (!FilesSecurity.CanRead(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFolder; } @@ -174,7 +174,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (!copy) { - if (!FilesSecurity.CanDelete(folder)) + if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -207,7 +207,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Status += string.Format("folder_{0}{1}", newFolderId, FileOperation.SPLIT_CHAR); } } - else if (!FilesSecurity.CanDelete(folder)) + else if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -236,7 +236,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } else { - if (!FilesSecurity.CanDelete(folder)) + if (!FilesSecurity.CanDelete(folder)) { Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder; } @@ -293,7 +293,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { Error = FilesCommonResource.ErrorMassage_FileNotFound; } - else if (!FilesSecurity.CanRead(file)) + else if (!FilesSecurity.CanRead(file)) { Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFile; } @@ -369,7 +369,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { if (_resolveType == FileConflictResolveType.Overwrite) { - if (!FilesSecurity.CanEdit(conflict)) + if (!FilesSecurity.CanEdit(conflict)) { Error = FilesCommonResource.ErrorMassage_SecurityException; } @@ -454,13 +454,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - private bool WithError(IServiceScope scope, IEnumerable files, out string error) + private bool WithError(IServiceScope scope, IEnumerable> files, out string error) { var entryManager = scope.ServiceProvider.GetService(); error = null; foreach (var file in files) { - if (!FilesSecurity.CanDelete(file)) + if (!FilesSecurity.CanDelete(file)) { error = FilesCommonResource.ErrorMassage_SecurityException_MoveFile; return true; diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index e04e77381c..8047b50b0b 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -104,7 +104,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected IFileDao FileDao { get; private set; } - protected ITagDao TagDao { get; private set; } + protected ITagDao TagDao { get; private set; } protected IProviderDao ProviderDao { get; private set; } @@ -154,7 +154,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations FolderDao = daoFactory.GetFolderDao(); FileDao = daoFactory.GetFileDao(); - TagDao = daoFactory.TagDao; + TagDao = daoFactory.GetTagDao(); ProviderDao = daoFactory.ProviderDao; FilesSecurity = fileSecurity; diff --git a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs index a363764c40..51379e1a62 100644 --- a/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs +++ b/products/ASC.Files/Server/Services/WCFService/IFileStorageService.cs @@ -32,30 +32,29 @@ using ASC.Files.Core; using ASC.Web.Files.Helpers; using ASC.Web.Files.Services.WCFService.FileOperations; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; namespace ASC.Web.Files.Services.WCFService { - public interface IFileStorageService + public interface IFileStorageService { #region Folder Manager - Folder GetFolder(string folderId); + Folder GetFolder(T folderId); - ItemList GetFolders(string parentId); + ItemList> GetFolders(T parentId); - ItemList GetPath(string folderId); + ItemList GetPath(T folderId); - Folder CreateNewFolder(string parentId, string title); + Folder CreateNewFolder(T parentId, string title); - Folder FolderRename(string folderId, string title); + Folder FolderRename(T folderId, string title); - DataWrapper GetFolderItems(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); + DataWrapper GetFolderItems(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); - object GetFolderItemsXml(string parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); + object GetFolderItemsXml(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); - ItemList GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string searchText); + ItemList> GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string searchText); ItemDictionary MoveOrCopyFilesCheck(ItemList items, string destFolderId); @@ -73,21 +72,21 @@ namespace ASC.Web.Files.Services.WCFService File GetFile(string fileId, int version); - File CreateNewFile(FileModel fileWrapper); + File CreateNewFile(FileModel fileWrapper); File FileRename(string fileId, string title); - KeyValuePair> UpdateToVersion(string fileId, int version); + KeyValuePair, ItemList>> UpdateToVersion(T fileId, int version); - KeyValuePair> CompleteVersion(string fileId, int version, bool continueVersion); + KeyValuePair, ItemList>> CompleteVersion(T fileId, int version, bool continueVersion); - string UpdateComment(string fileId, int version, string comment); + string UpdateComment(T fileId, int version, string comment); - ItemList GetFileHistory(string fileId); + ItemList> GetFileHistory(T fileId); - ItemList GetSiblingsFile(string fileId, string folderId, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); + ItemList> GetSiblingsFile(T fileId, T folderId, FilterType filter, bool subjectGroup, string subjectID, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy); - KeyValuePair TrackEditFile(string fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish); + KeyValuePair TrackEditFile(T fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish); ItemDictionary CheckEditing(ItemList filesId); @@ -113,7 +112,7 @@ namespace ASC.Web.Files.Services.WCFService #region Utils - ItemList ChangeOwner(ItemList items, Guid userId); + ItemList> ChangeOwner(ItemList items, Guid userId); ItemList BulkDownload(Dictionary items); @@ -167,9 +166,9 @@ namespace ASC.Web.Files.Services.WCFService ItemList GetThirdParty(); - ItemList GetThirdPartyFolder(int folderType); + ItemList> GetThirdPartyFolder(int folderType); - Folder SaveThirdParty(ThirdPartyParams thirdPartyParams); + Folder SaveThirdParty(ThirdPartyParams thirdPartyParams); object DeleteThirdParty(string providerId); diff --git a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs index c17db31a12..74d8f02b3d 100644 --- a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs +++ b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs @@ -35,7 +35,7 @@ namespace ASC.Web.Files.Services.WCFService public class DataWrapper { [DataMember(IsRequired = false, Name = "entries", EmitDefaultValue = false)] - public ItemList Entries { get; set; } + public ItemList> Entries { get; set; } [DataMember(IsRequired = false, Name = "total")] public int Total { get; set; } diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index 1d1000b270..f9ec4452e7 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -55,7 +55,6 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using File = ASC.Files.Core.File; using FileShare = ASC.Files.Core.Security.FileShare; namespace ASC.Web.Files.Utils @@ -71,7 +70,7 @@ namespace ASC.Web.Files.Utils DaoFactory = daoFactory; } - public bool FileLockedForMe(object fileId, Guid userId = default) + public bool FileLockedForMe(T fileId, Guid userId = default) { var app = ThirdPartySelector.GetAppByFileId(fileId.ToString()); if (app != null) @@ -80,12 +79,12 @@ namespace ASC.Web.Files.Utils } userId = userId == default ? AuthContext.CurrentAccount.ID : userId; - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var lockedBy = FileLockedBy(fileId, tagDao); return lockedBy != Guid.Empty && lockedBy != userId; } - public Guid FileLockedBy(object fileId, ITagDao tagDao) + public Guid FileLockedBy(T fileId, ITagDao tagDao) { var tagLock = tagDao.GetTags(fileId, FileEntryType.File, TagType.Locked).FirstOrDefault(); return tagLock != null ? tagLock.Owner : Guid.Empty; @@ -243,14 +242,14 @@ namespace ASC.Web.Files.Utils cache = AscCache.Memory; } - public IEnumerable GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) + public IEnumerable> GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) { total = 0; if (parent == null) throw new ArgumentNullException("parent", FilesCommonResource.ErrorMassage_FolderNotFound); var fileSecurity = FileSecurity; - var entries = Enumerable.Empty(); + var entries = Enumerable.Empty>(); searchInContent = searchInContent && filter != FilterType.ByExtension && !Equals(parent.ID, GlobalFolderHelper.FolderTrash); @@ -343,29 +342,29 @@ namespace ASC.Web.Files.Utils folders = fileSecurity.FilterRead(folders).ToList(); } - entries = entries.Concat(folders); + entries = entries.Concat(folders.Cast>()); } if (filter != FilterType.FoldersOnly && withSubfolders) { var files = DaoFactory.GetFileDao().GetFiles(rootKeys, filter, subjectGroup, subjectId, searchText, searchInContent).ToList(); files = fileSecurity.FilterRead(files).ToList(); - entries = entries.Concat(files); + entries = entries.Concat(files.Cast>()); } } - parent.TotalFiles = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalFiles : 1)); - parent.TotalSubFolders = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalSubFolders + 1 : 0)); + parent.TotalFiles = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalFiles : 1)); + parent.TotalSubFolders = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalSubFolders + 1 : 0)); } else if (parent.FolderType == FolderType.SHARE) { //share - var shared = (IEnumerable)fileSecurity.GetSharesForMe(filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders); + var shared = (IEnumerable>)fileSecurity.GetSharesForMe(filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders); entries = entries.Concat(shared); - parent.TotalFiles = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalFiles : 1)); - parent.TotalSubFolders = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalSubFolders + 1 : 0)); + parent.TotalFiles = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalFiles : 1)); + parent.TotalSubFolders = entries.Aggregate(0, (a, f) => a + (f.FileEntryType == FileEntryType.Folder ? ((Folder)f).TotalSubFolders + 1 : 0)); } else { @@ -410,7 +409,7 @@ namespace ASC.Web.Files.Utils if (0 < count) entries = entries.Take(count); } - SetFileStatus(entries.Where(r => r != null && r.ID != null && r.FileEntryType == FileEntryType.File).Select(r => r as File).ToList()); + SetFileStatus(entries.Where(r => r != null && r.ID != null && r.FileEntryType == FileEntryType.File).Select(r => r as File).ToList()); return entries; } @@ -433,12 +432,12 @@ namespace ASC.Web.Files.Utils var providers = providerDao.GetProvidersInfo(parent.RootFolderType, searchText); folderList = providers .Select(providerInfo => GetFakeThirdpartyFolder(providerInfo, parent.ID)) - .Where(r => fileSecurity.CanRead(r)).ToList(); + .Where(r => fileSecurity.CanRead(r)).ToList(); if (folderList.Any()) { - var securityDao = DaoFactory.SecurityDao; - securityDao.GetPureShareRecords(folderList.Cast().ToArray()) + var securityDao = DaoFactory.GetSecurityDao(); + securityDao.GetPureShareRecords(folderList.Cast>().ToArray()) //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) .Select(x => x.EntryId).Distinct().ToList() .ForEach(id => @@ -451,7 +450,7 @@ namespace ASC.Web.Files.Utils return folderList; } - public IEnumerable FilterEntries(IEnumerable entries, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent) + public IEnumerable> FilterEntries(IEnumerable> entries, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent) { if (entries == null || !entries.Any()) return entries; @@ -465,7 +464,7 @@ namespace ASC.Web.Files.Utils .ToList(); } - Func where = null; + Func, bool> where = null; switch (filter) { @@ -476,7 +475,7 @@ namespace ASC.Web.Files.Utils case FilterType.ArchiveOnly: case FilterType.FilesOnly: case FilterType.MediaOnly: - where = f => f.FileEntryType == FileEntryType.File && (((File)f).FilterType == filter || filter == FilterType.FilesOnly); + where = f => f.FileEntryType == FileEntryType.File && (((File)f).FilterType == filter || filter == FilterType.FilesOnly); break; case FilterType.FoldersOnly: where = f => f.FileEntryType == FileEntryType.Folder; @@ -499,11 +498,11 @@ namespace ASC.Web.Files.Utils return entries; } - public IEnumerable SortEntries(IEnumerable entries, OrderBy orderBy) + public IEnumerable> SortEntries(IEnumerable> entries, OrderBy orderBy) { if (entries == null || !entries.Any()) return entries; - Comparison sorter; + Comparison> sorter; if (orderBy == null) { @@ -534,7 +533,7 @@ namespace ASC.Web.Files.Utils { var cmp = 0; if (x.FileEntryType == FileEntryType.File && y.FileEntryType == FileEntryType.File) - cmp = c * ((File)x).ContentLength.CompareTo(((File)y).ContentLength); + cmp = c * ((File)x).ContentLength.CompareTo(((File)y).ContentLength); return cmp == 0 ? x.Title.EnumerableComparer(y.Title) : cmp; }; break; @@ -623,16 +622,16 @@ namespace ASC.Web.Files.Utils } - public void SetFileStatus(File file) + public void SetFileStatus(File file) { if (file == null || file.ID == null) return; - SetFileStatus(new List(1) { file }); + SetFileStatus(new List>(1) { file }); } - public void SetFileStatus(IEnumerable files) + public void SetFileStatus(IEnumerable> files) { - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var tagsNew = tagDao.GetNewTags(AuthContext.CurrentAccount.ID, files); var tagsLocked = tagDao.GetTags(TagType.Locked, files.ToArray()); @@ -654,12 +653,12 @@ namespace ASC.Web.Files.Utils } } - public bool FileLockedForMe(object fileId, Guid userId = default) + public bool FileLockedForMe(T fileId, Guid userId = default) { return LockerManager.FileLockedForMe(fileId, userId); } - public Guid FileLockedBy(object fileId, ITagDao tagDao) + public Guid FileLockedBy(T fileId, ITagDao tagDao) { return LockerManager.FileLockedBy(fileId, tagDao); } @@ -687,7 +686,7 @@ namespace ASC.Web.Files.Utils if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && !editLink && (!(fileSecurity.CanEdit(file) || fileSecurity.CanReview(file)) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (checkRight && FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (checkRight && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -800,7 +799,7 @@ namespace ASC.Web.Files.Utils } } - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); FileMarker.RemoveMarkAsNew(file); return file; } @@ -822,7 +821,7 @@ namespace ASC.Web.Files.Utils if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); var fileSecurity = FileSecurity; - if (!editLink && (!fileSecurity.CanEdit(file, userId) && !fileSecurity.CanReview(file, userId) && !fileSecurity.CanFillForms(file, userId) && !fileSecurity.CanComment(file, userId) || UserManager.GetUsers(userId).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (!editLink && (!fileSecurity.CanEdit(file, userId) && !fileSecurity.CanReview(file, userId) && !fileSecurity.CanFillForms(file, userId) && !fileSecurity.CanComment(file, userId) || UserManager.GetUsers(userId).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(file.ID, userId)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -849,7 +848,7 @@ namespace ASC.Web.Files.Utils fromFile = fileDao.GetFile(fromFile.ID, Math.Min(fromFile.Version, version)); if (fromFile == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && !editLink && (!FileSecurity.CanEdit(fromFile) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (checkRight && FileTracker.IsEditing(fromFile.ID)) throw new Exception(FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile); if (fromFile.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); @@ -890,7 +889,7 @@ namespace ASC.Web.Files.Utils newFile = fileDao.SaveFile(newFile, stream); } - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); SetFileStatus(newFile); @@ -914,7 +913,7 @@ namespace ASC.Web.Files.Utils ? fileDao.GetFile(fileId, version) : fileDao.GetFile(fileId); if (fileVersion == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); + if (checkRight && (!FileSecurity.CanEdit(fileVersion) || UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager))) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_EditFile); if (FileLockedForMe(fileVersion.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (fileVersion.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); if (fileVersion.ProviderEntry) throw new Exception(FilesCommonResource.ErrorMassage_BadRequest); @@ -953,8 +952,8 @@ namespace ASC.Web.Files.Utils var fileDao = DaoFactory.GetFileDao(); file = fileDao.GetFile(fileId); if (file == null) throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - if (!FileSecurity.CanEdit(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); - if (!FileSecurity.CanDelete(file) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); + if (!FileSecurity.CanEdit(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); + if (!FileSecurity.CanDelete(file) && UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFile); if (FileLockedForMe(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_LockedFile); if (file.ProviderEntry && FileTracker.IsEditing(file.ID)) throw new Exception(FilesCommonResource.ErrorMassage_UpdateEditingFile); if (file.RootFolderType == FolderType.TRASH) throw new Exception(FilesCommonResource.ErrorMassage_ViewTrashItem); diff --git a/products/ASC.Files/Server/Utils/FileConverter.cs b/products/ASC.Files/Server/Utils/FileConverter.cs index 17b843e9b1..5ae86affe7 100644 --- a/products/ASC.Files/Server/Utils/FileConverter.cs +++ b/products/ASC.Files/Server/Utils/FileConverter.cs @@ -57,7 +57,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using File = ASC.Files.Core.File; using SecurityContext = ASC.Core.SecurityContext; namespace ASC.Web.Files.Utils @@ -65,7 +64,7 @@ namespace ASC.Web.Files.Utils public class FileConverter { private static readonly object locker = new object(); - private static readonly IDictionary conversionQueue = new Dictionary(new FileComparer()); + private static readonly IDictionary, ConvertFileOperationResult> conversionQueue = new Dictionary, ConvertFileOperationResult>(new FileComparer()); private readonly ICache cache; private static Timer timer; @@ -165,7 +164,7 @@ namespace ASC.Web.Files.Utils get { return FileUtility.ExtsMustConvert.Any() && !string.IsNullOrEmpty(FilesLinkUtility.DocServiceConverterUrl); } } - public bool MustConvert(File file) + public bool MustConvert(File file) { if (file == null) return false; @@ -173,7 +172,7 @@ namespace ASC.Web.Files.Utils return FileUtility.ExtsMustConvert.Contains(ext); } - public bool EnableConvert(File file, string toExtension) + public bool EnableConvert(File file, string toExtension) { if (file == null || string.IsNullOrEmpty(toExtension)) { @@ -200,16 +199,16 @@ namespace ASC.Web.Files.Utils return FileUtility.ExtsConvertible.Keys.Contains(fileExtension) && FileUtility.ExtsConvertible[fileExtension].Contains(toExtension); } - public Stream Exec(File file) + public Stream Exec(File file) { return Exec(file, FileUtility.GetInternalExtension(file.Title)); } - public Stream Exec(File file, string toExtension) + public Stream Exec(File file, string toExtension) { if (!EnableConvert(file, toExtension)) { - var fileDao = DaoFactory.FileDao; + var fileDao = DaoFactory.GetFileDao(); return fileDao.GetFileStream(file); } @@ -234,7 +233,7 @@ namespace ASC.Web.Files.Utils { var fileDao = DaoFactory.GetFileDao(); var fileSecurity = FileSecurity; - if (!fileSecurity.CanRead(file)) + if (!fileSecurity.CanRead(file)) { var readLink = FileShareLink.Check(doc, true, fileDao, out file); if (file == null) @@ -299,7 +298,7 @@ namespace ASC.Web.Files.Utils if (timer == null) { - timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); + timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); } else { @@ -308,7 +307,7 @@ namespace ASC.Web.Files.Utils } } - public bool IsConverting(File file) + public bool IsConverting(File file) { if (!MustConvert(file) || !string.IsNullOrEmpty(file.ConvertedType)) { @@ -327,7 +326,7 @@ namespace ASC.Web.Files.Utils var file = pair.Key; var key = GetKey(file); var operation = cache.Get(key); - if (operation != null && (pair.Value || fileSecurity.CanRead(file))) + if (operation != null && (pair.Value || fileSecurity.CanRead(file))) { result.Add(operation); lock (locker) @@ -343,7 +342,7 @@ namespace ASC.Web.Files.Utils return result; } - private string FileJsonSerializer(File file, string folderTitle) + private string FileJsonSerializer(File file, string folderTitle) { if (file == null) return string.Empty; @@ -360,7 +359,7 @@ namespace ASC.Web.Files.Utils file.Version, file.FolderID, folderTitle ?? "", - File.Serialize(file).Replace('"', '\'')); + File.Serialize(file).Replace('"', '\'')); } private void CheckConvertFilesStatus(object _) @@ -376,7 +375,7 @@ namespace ASC.Web.Files.Utils try { - List> filesIsConverting = new List>(); + var filesIsConverting = new List>(); lock (locker) { timer.Change(Timeout.Infinite, Timeout.Infinite); @@ -398,11 +397,10 @@ namespace ASC.Web.Files.Utils return; } - //TODO: - //filesIsConverting = conversionQueue - // .Where(x => string.IsNullOrEmpty(x.Value.Processed)) - // .Select(x => x.Key) - // .ToList(); + filesIsConverting = conversionQueue + .Where(x => string.IsNullOrEmpty(x.Value.Processed)) + .Select(x => x.Key) + .ToList(); } var fileSecurity = FileSecurity; @@ -448,7 +446,7 @@ namespace ASC.Web.Files.Utils Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; - if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) + if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) { //No rights in CRM after upload before attach throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); @@ -525,7 +523,7 @@ namespace ASC.Web.Files.Utils continue; } - File newFile = null; + File newFile = null; var operationResultError = string.Empty; try @@ -555,9 +553,9 @@ namespace ASC.Web.Files.Utils { if (newFile != null) { - var folderDao = daoFactory.FolderDao; + var folderDao = daoFactory.GetFolderDao(); var folder = folderDao.GetFolder(newFile.FolderID); - var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; + var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; operationResult.Result = FileJsonSerializer(newFile, folderTitle); } @@ -605,7 +603,7 @@ namespace ASC.Web.Files.Utils File newFile = null; var newFileTitle = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetInternalExtension(file.Title)); - if (!FilesSettingsHelper.StoreOriginalFiles && fileSecurity.CanEdit(file)) + if (!FilesSettingsHelper.StoreOriginalFiles && fileSecurity.CanEdit(file)) { newFile = (File)file.Clone(); newFile.Version++; @@ -616,7 +614,7 @@ namespace ASC.Web.Files.Utils var parent = folderDao.GetFolder(file.FolderID); if (parent != null - && fileSecurity.CanCreate(parent)) + && fileSecurity.CanCreate(parent)) { folderId = parent.ID; } @@ -626,7 +624,7 @@ namespace ASC.Web.Files.Utils if (FilesSettingsHelper.UpdateIfExist && (parent != null && !folderId.Equals(parent.ID) || !file.ProviderEntry)) { newFile = fileDao.GetFile(folderId, newFileTitle); - if (newFile != null && fileSecurity.CanEdit(newFile) && !EntryManager.FileLockedForMe(newFile.ID) && !FileTracker.IsEditing(newFile.ID)) + if (newFile != null && fileSecurity.CanEdit(newFile) && !EntryManager.FileLockedForMe(newFile.ID) && !FileTracker.IsEditing(newFile.ID)) { newFile.Version++; } @@ -685,7 +683,7 @@ namespace ASC.Web.Files.Utils FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title); FileMarker.MarkAsNew(newFile); - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var tags = tagDao.GetTags(file.ID, FileEntryType.File, TagType.System).ToList(); if (tags.Any()) { @@ -696,20 +694,20 @@ namespace ASC.Web.Files.Utils return newFile; } - private static string GetKey(File f) + private static string GetKey(File f) { return string.Format("fileConvertation-{0}", f.ID); } - private class FileComparer : IEqualityComparer + private class FileComparer : IEqualityComparer> { - public bool Equals(File x, File y) + public bool Equals(File x, File y) { return x != null && y != null && Equals(x.ID, y.ID) && x.Version == y.Version; } - public int GetHashCode(File obj) + public int GetHashCode(File obj) { return obj.ID.GetHashCode() + obj.Version.GetHashCode(); } diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index c144bd9049..6c9111d9c7 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -44,10 +44,6 @@ using ASC.Web.Files.Classes; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using static ASC.Web.Files.Utils.FileMarker; - -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Utils { public class FileMarkerHelper @@ -61,13 +57,13 @@ namespace ASC.Web.Files.Utils Log = optionsMonitor.CurrentValue; } - internal void ExecMarkFileAsNew(AsyncTaskData obj) + internal void ExecMarkFileAsNew(AsyncTaskData obj) { try { using var scope = ServiceProvider.CreateScope(); var fileMarker = scope.ServiceProvider.GetService(); - fileMarker.ExecMarkFileAsNew(obj); + fileMarker.ExecMarkFileAsNew(obj); } catch (Exception e) { @@ -80,7 +76,7 @@ namespace ASC.Web.Files.Utils public class FileMarker { private static readonly object locker = new object(); - private readonly WorkerQueue tasks; + private readonly WorkerQueue> tasks; private readonly ICache cache; private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}"; @@ -104,7 +100,7 @@ namespace ASC.Web.Files.Utils CoreBaseSettings coreBaseSettings, AuthContext authContext, IServiceProvider serviceProvider, - WorkerQueueOptionsManager workerQueueOptionsManager, + WorkerQueueOptionsManager> workerQueueOptionsManager, FileMarkerHelper fileMarkerHelper) { TenantManager = tenantManager; @@ -120,7 +116,7 @@ namespace ASC.Web.Files.Utils tasks = workerQueueOptionsManager.Value; } - internal void ExecMarkFileAsNew(AsyncTaskData obj) + internal void ExecMarkFileAsNew(AsyncTaskData obj) { TenantManager.SetCurrentTenant(Convert.ToInt32(obj.TenantID)); @@ -136,7 +132,7 @@ namespace ASC.Web.Files.Utils var userIDs = obj.UserIDs; - var userEntriesData = new Dictionary>(); + var userEntriesData = new Dictionary>>(); if (obj.FileEntry.RootFolderType == FolderType.BUNCH) { @@ -144,7 +140,7 @@ namespace ASC.Web.Files.Utils parentFolders.Add(folderDao.GetFolder(GlobalFolder.GetFolderProjects(DaoFactory))); - var entries = new List { obj.FileEntry }; + var entries = new List> { obj.FileEntry }; entries = entries.Concat(parentFolders).ToList(); userIDs.ForEach(userID => @@ -163,7 +159,7 @@ namespace ASC.Web.Files.Utils if (!userIDs.Any()) { - userIDs = filesSecurity.WhoCanRead(obj.FileEntry).Where(x => x != obj.CurrentAccountId).ToList(); + userIDs = filesSecurity.WhoCanRead(obj.FileEntry).Where(x => x != obj.CurrentAccountId).ToList(); } if (obj.FileEntry.ProviderEntry) { @@ -172,7 +168,7 @@ namespace ASC.Web.Files.Utils parentFolders.ForEach(parentFolder => filesSecurity - .WhoCanRead(parentFolder) + .WhoCanRead(parentFolder) .Where(userID => userIDs.Contains(userID) && userID != obj.CurrentAccountId) .ToList() .ForEach(userID => @@ -180,7 +176,7 @@ namespace ASC.Web.Files.Utils if (userEntriesData.ContainsKey(userID)) userEntriesData[userID].Add(parentFolder); else - userEntriesData.Add(userID, new List { parentFolder }); + userEntriesData.Add(userID, new List> { parentFolder }); }) ); @@ -195,7 +191,7 @@ namespace ASC.Web.Files.Utils var userFolderId = folderDao.GetFolderIDUser(false, userID); if (Equals(userFolderId, 0)) continue; - Folder rootFolder = null; + Folder rootFolder = null; if (obj.FileEntry.ProviderEntry) { rootFolder = obj.FileEntry.RootFolderCreator == userID @@ -216,7 +212,7 @@ namespace ASC.Web.Files.Utils if (userEntriesData.ContainsKey(userID)) userEntriesData[userID].Add(rootFolder); else - userEntriesData.Add(userID, new List { rootFolder }); + userEntriesData.Add(userID, new List> { rootFolder }); RemoveFromCahce(rootFolder.ID, userID); } @@ -228,13 +224,13 @@ namespace ASC.Web.Files.Utils if (obj.FileEntry.ProviderEntry) { - var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); + var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); userIDs.ForEach(userID => { if (userEntriesData.ContainsKey(userID)) userEntriesData[userID].Add(commonFolder); else - userEntriesData.Add(userID, new List { commonFolder }); + userEntriesData.Add(userID, new List> { commonFolder }); RemoveFromCahce(GlobalFolder.GetFolderCommon(this, DaoFactory), userID); }); @@ -246,11 +242,11 @@ namespace ASC.Web.Files.Utils if (userEntriesData.ContainsKey(userID)) userEntriesData[userID].Add(obj.FileEntry); else - userEntriesData.Add(userID, new List { obj.FileEntry }); + userEntriesData.Add(userID, new List> { obj.FileEntry }); }); } - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var newTags = new List(); var updateTags = new List(); @@ -281,26 +277,26 @@ namespace ASC.Web.Files.Utils tagDao.SaveTags(newTags); } - public void MarkAsNew(FileEntry fileEntry, List userIDs = null) + public void MarkAsNew(FileEntry fileEntry, List userIDs = null) { if (CoreBaseSettings.Personal) return; if (fileEntry == null) return; userIDs ??= new List(); - var taskData = ServiceProvider.GetService(); - taskData.FileEntry = (FileEntry)fileEntry.Clone(); + var taskData = ServiceProvider.GetService>(); + taskData.FileEntry = (FileEntry)fileEntry.Clone(); taskData.UserIDs = userIDs; if (fileEntry.RootFolderType == FolderType.BUNCH && !userIDs.Any()) { - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); var path = folderDao.GetBunchObjectID(fileEntry.RootFolderId); var projectID = path.Split('/').Last(); if (string.IsNullOrEmpty(projectID)) return; - var projectTeam = FileSecurity.WhoCanRead(fileEntry) + var projectTeam = FileSecurity.WhoCanRead(fileEntry) .Where(x => x != AuthContext.CurrentAccount.ID).ToList(); if (!projectTeam.Any()) return; @@ -313,11 +309,11 @@ namespace ASC.Web.Files.Utils tasks.Add(taskData); if (!tasks.IsStarted) - tasks.Start(FileMarkerHelper.ExecMarkFileAsNew); + tasks.Start(FileMarkerHelper.ExecMarkFileAsNew); } } - public void RemoveMarkAsNew(FileEntry fileEntry, Guid userID = default) + public void RemoveMarkAsNew(FileEntry fileEntry, Guid userID = default) { if (CoreBaseSettings.Personal) return; @@ -325,11 +321,11 @@ namespace ASC.Web.Files.Utils if (fileEntry == null) return; - var tagDao = DaoFactory.TagDao; - var folderDao = DaoFactory.FolderDao; + var tagDao = DaoFactory.GetTagDao(); + var folderDao = DaoFactory.GetFolderDao(); if (!tagDao.GetNewTags(userID, fileEntry).Any()) return; - object folderID; + T folderID; int valueNew; var userFolderId = folderDao.GetFolderIDUser(false, userID); @@ -337,7 +333,7 @@ namespace ASC.Web.Files.Utils if (fileEntry.FileEntryType == FileEntryType.File) { - folderID = ((File)fileEntry).FolderID; + folderID = ((File)fileEntry).FolderID; removeTags.Add(Tag.New(userID, fileEntry)); valueNew = 1; @@ -346,14 +342,14 @@ namespace ASC.Web.Files.Utils { folderID = fileEntry.ID; - var listTags = tagDao.GetNewTags(userID, (Folder)fileEntry, true).ToList(); + var listTags = tagDao.GetNewTags(userID, (Folder)fileEntry, true).ToList(); valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.ID)).Count; if (Equals(fileEntry.ID, userFolderId) || Equals(fileEntry.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(fileEntry.ID, GlobalFolder.GetFolderShare(DaoFactory))) { var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder); - var providerFolderTags = folderTags.Select(tag => new KeyValuePair(tag, folderDao.GetFolder(tag.EntryId))) + var providerFolderTags = folderTags.Select(tag => new KeyValuePair>(tag, folderDao.GetFolder(tag.EntryId))) .Where(pair => pair.Value != null && pair.Value.ProviderEntry).ToList(); foreach (var providerFolderTag in providerFolderTags) @@ -370,14 +366,14 @@ namespace ASC.Web.Files.Utils parentFolders.Reverse(); var rootFolder = parentFolders.LastOrDefault(); - object rootFolderId = null; - object cacheFolderId = null; + T rootFolderId = default; + T cacheFolderId = default; if (rootFolder == null) { } else if (rootFolder.RootFolderType == FolderType.BUNCH) { - cacheFolderId = rootFolderId = GlobalFolder.GetFolderProjects(DaoFactory); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderProjects(DaoFactory); } else if (rootFolder.RootFolderType == FolderType.COMMON) { @@ -392,13 +388,13 @@ namespace ASC.Web.Files.Utils cacheFolderId = rootFolderId = userFolderId; else if (!rootFolder.ProviderEntry && !Equals(rootFolder.RootFolderId, userFolderId) || rootFolder.ProviderEntry && rootFolder.RootFolderCreator != userID) - cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderShare(DaoFactory); else cacheFolderId = userFolderId; } else if (rootFolder.RootFolderType == FolderType.SHARE) { - cacheFolderId = GlobalFolder.GetFolderShare(DaoFactory); + cacheFolderId = GlobalFolder.GetFolderShare(DaoFactory); } if (rootFolderId != null) @@ -436,11 +432,11 @@ namespace ASC.Web.Files.Utils tagDao.RemoveTags(removeTags); } - public void RemoveMarkAsNewForAll(FileEntry fileEntry) + public void RemoveMarkAsNewForAll(FileEntry fileEntry) { List userIDs; - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var tags = tagDao.GetTags(fileEntry.ID, fileEntry.FileEntryType == FileEntryType.File ? FileEntryType.File : FileEntryType.Folder, TagType.New); userIDs = tags.Select(tag => tag.Owner).Distinct().ToList(); @@ -454,8 +450,8 @@ namespace ASC.Web.Files.Utils { var rootIds = new List { - GlobalFolder.GetFolderMy(this, DaoFactory), - GlobalFolder.GetFolderCommon(this, DaoFactory), + GlobalFolder.GetFolderMy(this, DaoFactory), + GlobalFolder.GetFolderCommon(this, DaoFactory), GlobalFolder.GetFolderShare(DaoFactory), GlobalFolder.GetFolderProjects(DaoFactory) }; @@ -495,20 +491,20 @@ namespace ASC.Web.Files.Utils return news; } - public List MarkedItems(Folder folder) + public List> MarkedItems(Folder folder) { if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); - if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, GlobalFolder.GetFolderTrash(DaoFactory.FolderDao))) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem); + if (!FileSecurity.CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); + if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, GlobalFolder.GetFolderTrash(DaoFactory))) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem); - var entryTags = new Dictionary(); + var entryTags = new Dictionary, Tag>(); - var tagDao = DaoFactory.TagDao; + var tagDao = DaoFactory.GetTagDao(); var fileDao = DaoFactory.GetFileDao(); var folderDao = DaoFactory.GetFolderDao(); var tags = (tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folder, true) ?? new List()).ToList(); - if (!tags.Any()) return new List(); + if (!tags.Any()) return new List>(); if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderShare(DaoFactory))) { @@ -533,7 +529,7 @@ namespace ASC.Web.Files.Utils { var entry = tag.EntryType == FileEntryType.File ? fileDao.GetFile((T)tag.EntryId) - : (FileEntry)folderDao.GetFolder((T)tag.EntryId); + : (FileEntry)folderDao.GetFolder((T)tag.EntryId); if (entry != null) { entryTags.Add(entry, tag); @@ -549,15 +545,15 @@ namespace ASC.Web.Files.Utils var entry = entryTag.Key; var parentId = entry.FileEntryType == FileEntryType.File - ? ((File)entry).FolderID - : ((Folder)entry).ParentFolderID; + ? ((File)entry).FolderID + : ((Folder)entry).ParentFolderID; var parentEntry = entryTags.Keys.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, parentId)); if (parentEntry != null) entryTags[parentEntry].Count -= entryTag.Value.Count; } - var result = new List(); + var result = new List>(); foreach (var entryTag in entryTags) { @@ -575,7 +571,7 @@ namespace ASC.Web.Files.Utils return result; } - public IEnumerable SetTagsNew(Folder parent, IEnumerable entries) + public IEnumerable> SetTagsNew(Folder parent, IEnumerable> entries) { var tagDao = DaoFactory.GetTagDao(); var folderDao = DaoFactory.GetFolderDao(); @@ -641,7 +637,7 @@ namespace ASC.Web.Files.Utils if (parentTreeTag == null) { - if (fileSecurity.CanRead(folderFromList)) + if (fileSecurity.CanRead(folderFromList)) { tagDao.SaveTags(Tag.New(AuthContext.CurrentAccount.ID, folderFromList, -diff)); } @@ -672,7 +668,7 @@ namespace ASC.Web.Files.Utils if (entry.FileEntryType == FileEntryType.Folder) { - ((Folder)entry).NewForMe = curTag != null ? curTag.Count : 0; + ((Folder)entry).NewForMe = curTag != null ? curTag.Count : 0; } else if (curTag != null) { @@ -708,38 +704,47 @@ namespace ASC.Web.Files.Utils var key = string.Format(CacheKeyFormat, userId, folderId); cache.Remove(key); } - - - public class AsyncTaskData - { - public AsyncTaskData(TenantManager tenantManager, AuthContext authContext) - { - TenantID = tenantManager.GetCurrentTenant().TenantId; - CurrentAccountId = authContext.CurrentAccount.ID; - } - - public int TenantID { get; private set; } - - public FileEntry FileEntry { get; set; } - - public List UserIDs { get; set; } - - public Guid CurrentAccountId { get; set; } - } } + + public class AsyncTaskData + { + public AsyncTaskData(TenantManager tenantManager, AuthContext authContext) + { + TenantID = tenantManager.GetCurrentTenant().TenantId; + CurrentAccountId = authContext.CurrentAccount.ID; + } + + public int TenantID { get; private set; } + + public FileEntry FileEntry { get; set; } + + public List UserIDs { get; set; } + + public Guid CurrentAccountId { get; set; } + } + public static class FileMarkerExtention { public static DIHelper AddFileMarkerService(this DIHelper services) + { + + return services + .AddFileMarkerService() + .AddFileMarkerService() + ; + } + + public static DIHelper AddFileMarkerService(this DIHelper services) { _ = services - .TryAddTransient() + .TryAddTransient>() .TryAddScoped() .TryAddSingleton() - .TryAddSingleton>() - .TryAddSingleton>() - .AddSingleton>, ConfigureWorkerQueue>(); + .TryAddSingleton>>() + .TryAddSingleton>>() + .AddSingleton>>, ConfigureWorkerQueue>>(); - _ = services.Configure>(r => + _ = services.Configure>>(r => { r.workerCount = 1; r.waitInterval = (int)TimeSpan.FromSeconds(60).TotalMilliseconds; diff --git a/products/ASC.Files/Server/Utils/FileShareLink.cs b/products/ASC.Files/Server/Utils/FileShareLink.cs index fed40ac8ed..cd3f3fb4de 100644 --- a/products/ASC.Files/Server/Utils/FileShareLink.cs +++ b/products/ASC.Files/Server/Utils/FileShareLink.cs @@ -106,11 +106,11 @@ namespace ASC.Web.Files.Utils if (file == null) return FileShare.Restrict; var filesSecurity = FileSecurity; - if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; - if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; - if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; - if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; - if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; + if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite; + if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review; + if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms; + if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment; + if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read; return FileShare.Restrict; } } diff --git a/products/ASC.Files/Server/Utils/FileSharing.cs b/products/ASC.Files/Server/Utils/FileSharing.cs index 863c4fae87..69f383220a 100644 --- a/products/ASC.Files/Server/Utils/FileSharing.cs +++ b/products/ASC.Files/Server/Utils/FileSharing.cs @@ -48,7 +48,7 @@ using Microsoft.Extensions.Options; namespace ASC.Web.Files.Utils { - public class FileSharingAceHelper + public class FileSharingAceHelper { public FileSecurity FileSecurity { get; } public CoreBaseSettings CoreBaseSettings { get; } @@ -85,10 +85,10 @@ namespace ASC.Web.Files.Utils FileSharingHelper = fileSharingHelper; } - public bool SetAceObject(List aceWrappers, FileEntry entry, bool notify, string message) + public bool SetAceObject(List aceWrappers, FileEntry entry, bool notify, string message) { if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest); - if (!FileSharingHelper.CanSetAccess(entry)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); + if (!FileSharingHelper.CanSetAccess(entry)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); var fileSecurity = FileSecurity; @@ -166,10 +166,10 @@ namespace ASC.Web.Files.Utils if (recipients.Any()) { if (entryType == FileEntryType.File - || ((Folder)entry).TotalSubFolders + ((Folder)entry).TotalFiles > 0 + || ((Folder)entry).TotalSubFolders + ((Folder)entry).TotalFiles > 0 || entry.ProviderEntry) { - FileMarker.MarkAsNew(entry, recipients.Keys.ToList()); + FileMarker.MarkAsNew(entry, recipients.Keys.ToList()); } if (entry.RootFolderType == FolderType.USER @@ -184,7 +184,7 @@ namespace ASC.Web.Files.Utils return changed; } - public void RemoveAce(List entries) + public void RemoveAce(List> entries) { var fileSecurity = FileSecurity; @@ -229,13 +229,13 @@ namespace ASC.Web.Files.Utils public AuthContext AuthContext { get; } public UserManager UserManager { get; } - public bool CanSetAccess(FileEntry entry) + public bool CanSetAccess(FileEntry entry) { return entry != null && (entry.RootFolderType == FolderType.COMMON && Global.IsAdministrator || entry.RootFolderType == FolderType.USER - && (Equals(entry.RootFolderId, GlobalFolderHelper.GetFolderMy()) || FileSecurity.CanEdit(entry)) + && (Equals(entry.RootFolderId, GlobalFolderHelper.GetFolderMy()) || FileSecurity.CanEdit(entry)) && !UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager)); } } @@ -274,15 +274,15 @@ namespace ASC.Web.Files.Utils Logger = optionsMonitor.CurrentValue; } - public bool CanSetAccess(FileEntry entry) + public bool CanSetAccess(FileEntry entry) { - return FileSharingHelper.CanSetAccess(entry); + return FileSharingHelper.CanSetAccess(entry); } - public List GetSharedInfo(FileEntry entry) + public List GetSharedInfo(FileEntry entry) { if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest); - if (!CanSetAccess(entry)) + if (!CanSetAccess(entry)) { Logger.ErrorFormat("User {0} can't get shared info for {1} {2}", AuthContext.CurrentAccount.ID, (entry.FileEntryType == FileEntryType.File ? "file" : "folder"), entry.ID); throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException); @@ -325,7 +325,7 @@ namespace ASC.Web.Files.Utils if (g.ID == Constants.LostGroupInfo.ID) { - fileSecurity.RemoveSubject(r.Subject); + fileSecurity.RemoveSubject(r.Subject); continue; } } @@ -347,7 +347,7 @@ namespace ASC.Web.Files.Utils if (entry.FileEntryType == FileEntryType.File && result.All(w => w.SubjectId != FileConstant.ShareLinkId) && entry.FileEntryType == FileEntryType.File - && !((File)entry).Encrypted) + && !((File)entry).Encrypted) { var w = new AceWrapper { @@ -421,8 +421,8 @@ namespace ASC.Web.Files.Utils var result = new List(); - var folderDao = DaoFactory.FolderDao; - var fileDao = DaoFactory.FileDao; + var folderDao = DaoFactory.GetFolderDao(); + var fileDao = DaoFactory.GetFileDao(); foreach (var objectId in objectIds) { @@ -432,16 +432,16 @@ namespace ASC.Web.Files.Utils } var entryType = objectId.StartsWith("file_") ? FileEntryType.File : FileEntryType.Folder; - var entryId = objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length); + var entryId = (T)Convert.ChangeType(objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length), typeof(T)); var entry = entryType == FileEntryType.File - ? (FileEntry)fileDao.GetFile(entryId) - : (FileEntry)folderDao.GetFolder(entryId); + ? fileDao.GetFile(entryId) + : (FileEntry)folderDao.GetFolder(entryId); IEnumerable acesForObject; try { - acesForObject = GetSharedInfo(entry); + acesForObject = GetSharedInfo(entry); } catch (Exception e) { @@ -570,7 +570,8 @@ namespace ASC.Web.Files.Utils } public static DIHelper AddFileSharingAceHelperService(this DIHelper services) { - services.TryAddScoped(); + services.TryAddScoped>(); + services.TryAddScoped>(); return services .AddFileSecurityService() diff --git a/products/ASC.Files/Server/Utils/FileUploader.cs b/products/ASC.Files/Server/Utils/FileUploader.cs index 1c9e2f7158..7ea4874299 100644 --- a/products/ASC.Files/Server/Utils/FileUploader.cs +++ b/products/ASC.Files/Server/Utils/FileUploader.cs @@ -48,8 +48,6 @@ using ASC.Web.Studio.Utility; using Microsoft.Extensions.DependencyInjection; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Utils { public class FileUploader @@ -128,7 +126,7 @@ namespace ASC.Web.Files.Utils var dao = DaoFactory.GetFileDao(); file = dao.SaveFile(file, data); - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); if (FileConverter.EnableAsUploaded && FileConverter.MustConvert(file)) FileConverter.ExecAsync(file, deleteConvertStatus); @@ -184,7 +182,7 @@ namespace ASC.Web.Files.Utils private bool CanEdit(File file) { return file != null - && FileSecurity.CanEdit(file) + && FileSecurity.CanEdit(file) && !UserManager.GetUsers(AuthContext.CurrentAccount.ID).IsVisitor(UserManager) && !EntryManager.FileLockedForMe(file.ID) && !FileTracker.IsEditing(file.ID) @@ -200,7 +198,7 @@ namespace ASC.Web.Files.Utils if (folder == null) throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound); - if (!FileSecurity.CanCreate(folder)) + if (!FileSecurity.CanCreate(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); if (relativePath != null && relativePath.Any()) @@ -235,7 +233,7 @@ namespace ASC.Web.Files.Utils #region chunked upload - public File VerifyChunkedUpload(string folderId, string fileName, long fileSize, bool updateIfExists, string relativePath = null) + public File VerifyChunkedUpload(T folderId, string fileName, long fileSize, bool updateIfExists, string relativePath = null) { var maxUploadSize = GetMaxFileSize(folderId, true); @@ -300,7 +298,7 @@ namespace ASC.Web.Files.Utils if (uploadSession.BytesUploaded == uploadSession.BytesTotal) { - FileMarker.MarkAsNew(uploadSession.File); + FileMarker.MarkAsNew(uploadSession.File); ChunkedUploadSessionHolder.RemoveSession(uploadSession); } else @@ -323,9 +321,9 @@ namespace ASC.Web.Files.Utils ChunkedUploadSessionHolder.RemoveSession(uploadSession); } - private long GetMaxFileSize(object folderId, bool chunkedUpload = false) + private long GetMaxFileSize(T folderId, bool chunkedUpload = false) { - var folderDao = DaoFactory.FolderDao; + var folderDao = DaoFactory.GetFolderDao(); return folderDao.GetMaxUploadSize(folderId, chunkedUpload); } From ae9a5003f3fc0eb42b1cfb44a6a8fc815ae189f6 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Thu, 5 Mar 2020 10:24:50 +0300 Subject: [PATCH 06/30] Files: refactoring --- .../Server/Controllers/FilesController.cs | 102 +-- .../Server/Core/Dao/TeamlabDao/FileDao.cs | 8 +- .../Server/Core/Dao/TeamlabDao/TagDao.cs | 188 ++++- products/ASC.Files/Server/Core/Entries/Tag.cs | 19 +- .../Server/Core/FileStorageService.cs | 8 +- products/ASC.Files/Server/Helpers/Global.cs | 1 + .../Server/HttpHandlers/FileHandler.ashx.cs | 2 +- .../Server/Model/FileEntryWrapper.cs | 6 +- .../Server/Model/FileOperationWraper.cs | 18 +- .../ASC.Files/Server/Model/FileWrapper.cs | 14 +- .../Server/Model/FolderContentWrapper.cs | 22 +- .../ASC.Files/Server/Model/FolderWrapper.cs | 14 +- .../Services/DocumentService/Configuration.cs | 2 - .../WCFService/FileEntrySerializer.cs | 4 +- .../FileOperations/FileMoveCopyOperation.cs | 2 +- .../ASC.Files/Server/Utils/EntryManager.cs | 2 +- .../ASC.Files/Server/Utils/FileConverter.cs | 714 +++++++++--------- products/ASC.Files/Server/Utils/FileMarker.cs | 62 +- 18 files changed, 711 insertions(+), 477 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index debbf06fe3..79d7dd7cf6 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -205,9 +205,9 @@ namespace ASC.Api.Documents /// Folders /// My folder contents [Read("@my")] - public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.FolderMy, userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderMy(), userIdOrGroupId, filterType); } /// @@ -219,9 +219,9 @@ namespace ASC.Api.Documents /// Folders /// Projects folder contents [Read("@projects")] - public FolderContentWrapper GetProjectsFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetProjectsFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.FolderProjects, userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderProjects(), userIdOrGroupId, filterType); } @@ -234,9 +234,9 @@ namespace ASC.Api.Documents /// Folders /// Common folder contents [Read("@common")] - public FolderContentWrapper GetCommonFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetCommonFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.FolderCommon, userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderCommon(), userIdOrGroupId, filterType); } /// @@ -248,9 +248,9 @@ namespace ASC.Api.Documents /// Folders /// Shared folder contents [Read("@share")] - public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.FolderShare, userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderShare(), userIdOrGroupId, filterType); } /// @@ -262,9 +262,9 @@ namespace ASC.Api.Documents /// Folders /// Trash folder contents [Read("@trash")] - public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.FolderTrash, userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderTrash(), userIdOrGroupId, filterType); } /// @@ -279,13 +279,13 @@ namespace ASC.Api.Documents /// Filter type /// Folder contents [Read("{folderId}", order: int.MaxValue)] - public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType) { return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); } [Read("{folderId:int}", order: int.MaxValue)] - public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType) { return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); } @@ -405,7 +405,7 @@ namespace ASC.Api.Documents /// Uploads /// [Create("@my/insert")] - public FileWrapper InsertFileToMy(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + public FileWrapper InsertFileToMy(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { return InsertFile(GlobalFolderHelper.FolderMy.ToString(), file, title, createNewIfExist, keepConvertStatus); } @@ -420,7 +420,7 @@ namespace ASC.Api.Documents /// Uploads /// [Create("@common/insert")] - public FileWrapper InsertFileToCommon(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + public FileWrapper InsertFileToCommon(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { return InsertFile(GlobalFolderHelper.FolderCommon.ToString(), file, title, createNewIfExist, keepConvertStatus); } @@ -436,7 +436,7 @@ namespace ASC.Api.Documents /// Uploads /// [Create("{folderId}/insert")] - public FileWrapper InsertFile(string folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + public FileWrapper InsertFile(string folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { try { @@ -462,7 +462,7 @@ namespace ASC.Api.Documents /// /// false [Update("{fileId}/update")] - public FileWrapper UpdateFileStream(Stream file, string fileId, bool encrypted = false) + public FileWrapper UpdateFileStream(Stream file, string fileId, bool encrypted = false) { try { @@ -488,7 +488,7 @@ namespace ASC.Api.Documents /// Files /// [Update("file/{fileId}/saveediting")] - public FileWrapper SaveEditing(string fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) + public FileWrapper SaveEditing(string fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) { return FileWrapperHelper.Get(FileStorageService.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave)); } @@ -624,7 +624,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@my/text")] - public FileWrapper CreateTextFileInMy(string title, string content) + public FileWrapper CreateTextFileInMy(string title, string content) { return CreateTextFile(GlobalFolderHelper.FolderMy.ToString(), title, content); } @@ -638,7 +638,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@common/text")] - public FileWrapper CreateTextFileInCommon(string title, string content) + public FileWrapper CreateTextFileInCommon(string title, string content) { return CreateTextFile(GlobalFolderHelper.FolderCommon.ToString(), title, content); } @@ -653,7 +653,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("{folderId}/text")] - public FileWrapper CreateTextFile(string folderId, string title, string content) + public FileWrapper CreateTextFile(string folderId, string title, string content) { if (title == null) throw new ArgumentNullException("title"); //Try detect content @@ -668,11 +668,11 @@ namespace ASC.Api.Documents return CreateFile(folderId, title, content, extension); } - private FileWrapper CreateFile(T folderId, string title, string content, string extension) + private FileWrapper CreateFile(T folderId, string title, string content, string extension) { using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) { - var file = FileUploader.Exec(folderId.ToString(), + var file = FileUploader.Exec(folderId, title.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? title : (title + extension), memStream.Length, memStream); return FileWrapperHelper.Get(file); @@ -689,7 +689,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("{folderId}/html")] - public FileWrapper CreateHtmlFile(string folderId, string title, string content) + public FileWrapper CreateHtmlFile(string folderId, string title, string content) { if (title == null) throw new ArgumentNullException("title"); return CreateFile(folderId, title, content, ".html"); @@ -704,7 +704,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@my/html")] - public FileWrapper CreateHtmlFileInMy(string title, string content) + public FileWrapper CreateHtmlFileInMy(string title, string content) { return CreateHtmlFile(GlobalFolderHelper.FolderMy.ToString(), title, content); } @@ -719,7 +719,7 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@common/html")] - public FileWrapper CreateHtmlFileInCommon(string title, string content) + public FileWrapper CreateHtmlFileInCommon(string title, string content) { return CreateHtmlFile(GlobalFolderHelper.FolderCommon.ToString(), title, content); } @@ -736,7 +736,7 @@ namespace ASC.Api.Documents /// Title of new folder /// New folder contents [Create("folder/{folderId}")] - public FolderWrapper CreateFolder(string folderId, string title) + public FolderWrapper CreateFolder(string folderId, string title) { var folder = FileStorageService.CreateNewFolder(folderId, title); return FolderWrapperHelper.Get(folder); @@ -751,7 +751,7 @@ namespace ASC.Api.Documents /// 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 [Create("@my/file")] - public FileWrapper CreateFile(string title) + public FileWrapper CreateFile(string title) { return CreateFile(GlobalFolderHelper.FolderMy.ToString(), title); } @@ -766,7 +766,7 @@ namespace ASC.Api.Documents /// 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 [Create("{folderId}/file")] - public FileWrapper CreateFile(string folderId, string title) + public FileWrapper CreateFile(string folderId, string title) { var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); return FileWrapperHelper.Get(file); @@ -783,7 +783,7 @@ namespace ASC.Api.Documents /// New title /// Folder contents [Update("folder/{folderId}")] - public FolderWrapper RenameFolder(string folderId, string title) + public FolderWrapper RenameFolder(string folderId, string title) { var folder = FileStorageService.FolderRename(folderId, title); return FolderWrapperHelper.Get(folder); @@ -796,7 +796,7 @@ namespace ASC.Api.Documents /// Folders /// Folder info [Read("folder/{folderId}")] - public FolderWrapper GetFolderInfo(string folderId) + public FolderWrapper GetFolderInfo(string folderId) { var folder = FileStorageService.GetFolder(folderId).NotFoundIfNull("Folder not found"); @@ -810,7 +810,7 @@ namespace ASC.Api.Documents /// Folders /// Parent folders [Read("folder/{folderId}/path")] - public IEnumerable GetFolderPath(string folderId) + public IEnumerable> GetFolderPath(string folderId) { return EntryManager.GetBreadCrumbs(folderId).Select(FolderWrapperHelper.Get); } @@ -822,7 +822,7 @@ namespace ASC.Api.Documents /// Files /// File info [Read("file/{fileId}")] - public FileWrapper GetFileInfo(string fileId, int version = -1) + public FileWrapper GetFileInfo(string fileId, int version = -1) { var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); return FileWrapperHelper.Get(file); @@ -835,7 +835,7 @@ namespace ASC.Api.Documents /// Files /// File info [Read("file/{fileId:int}")] - public FileWrapper GetFileInfo(int fileId, int version = -1) + public FileWrapper GetFileInfo(int fileId, int version = -1) { var file = FileStorageServiceInt.GetFile(fileId, version).NotFoundIfNull("File not found"); return FileWrapperHelper.Get(file); @@ -851,7 +851,7 @@ namespace ASC.Api.Documents /// File last version number /// File info [Update("file/{fileId}")] - public FileWrapper UpdateFile(string fileId, string title, int lastVersion) + public FileWrapper UpdateFile(string fileId, string title, int lastVersion) { if (!string.IsNullOrEmpty(title)) FileStorageService.FileRename(fileId.ToString(CultureInfo.InvariantCulture), title); @@ -872,7 +872,7 @@ namespace ASC.Api.Documents /// Don't move to the Recycle Bin /// Operation result [Delete("file/{fileId}")] - public IEnumerable DeleteFile(string fileId, bool deleteAfter, bool immediately) + public IEnumerable> DeleteFile(string fileId, bool deleteAfter, bool immediately) { var model = new DeleteBatchModel { @@ -942,7 +942,7 @@ namespace ASC.Api.Documents /// Don't move to the Recycle Bin /// Operation result [Delete("folder/{folderId}")] - public IEnumerable DeleteFolder(string folderId, bool deleteAfter, bool immediately) + public IEnumerable> DeleteFolder(string folderId, bool deleteAfter, bool immediately) { var model = new DeleteBatchModel { @@ -963,7 +963,7 @@ namespace ASC.Api.Documents /// File ID list /// Conflicts file ids [Read("fileops/move")] - public IEnumerable MoveOrCopyBatchCheck(BatchModel batchModel) + public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) { var itemList = new ItemList(); @@ -988,7 +988,7 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/move")] - public IEnumerable MoveBatchItems(BatchModel batchModel) + public IEnumerable> MoveBatchItems(BatchModel batchModel) { var itemList = new ItemList(); @@ -1010,7 +1010,7 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/copy")] - public IEnumerable CopyBatchItems(BatchModel batchModel) + public IEnumerable> CopyBatchItems(BatchModel batchModel) { var itemList = new ItemList(); @@ -1027,7 +1027,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/markasread")] - public IEnumerable MarkAsRead(BaseBatchModel model) + public IEnumerable> MarkAsRead(BaseBatchModel model) { var itemList = new ItemList(); @@ -1044,7 +1044,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/terminate")] - public IEnumerable TerminateTasks() + public IEnumerable> TerminateTasks() { return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); } @@ -1057,7 +1057,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Read("fileops")] - public IEnumerable GetOperationStatuses() + public IEnumerable> GetOperationStatuses() { return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); } @@ -1072,7 +1072,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/bulkdownload")] - public IEnumerable BulkDownload(DownloadModel model) + public IEnumerable> BulkDownload(DownloadModel model) { var itemList = new Dictionary(); @@ -1105,7 +1105,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/delete")] - public IEnumerable DeleteBatchItems(DeleteBatchModel batch) + public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) { var itemList = new ItemList(); @@ -1122,7 +1122,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/emptytrash")] - public IEnumerable EmptyTrash() + public IEnumerable> EmptyTrash() { return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } @@ -1135,7 +1135,7 @@ namespace ASC.Api.Documents /// File ID /// File information [Read("file/{fileId}/history")] - public IEnumerable GetFileVersionInfo(string fileId) + public IEnumerable> GetFileVersionInfo(string fileId) { var files = FileStorageService.GetFileHistory(fileId); return files.Select(FileWrapperHelper.Get); @@ -1150,7 +1150,7 @@ namespace ASC.Api.Documents /// Files /// [Update("file/{fileId}/history")] - public IEnumerable ChangeHistory(string fileId, int version, bool continueVersion) + public IEnumerable> ChangeHistory(string fileId, int version, bool continueVersion) { var history = FileStorageService.CompleteVersion(fileId, version, continueVersion).Value; return history.Select(FileWrapperHelper.Get); @@ -1378,7 +1378,7 @@ namespace ASC.Api.Documents /// List of provider key: DropboxV2, Box, WebDav, Yandex, OneDrive, SharePoint, GoogleDrive /// [Create("thirdparty")] - public FolderWrapper SaveThirdParty( + public FolderWrapper SaveThirdParty( string url, string login, string password, @@ -1547,7 +1547,7 @@ namespace ASC.Api.Documents } - private FolderContentWrapper ToFolderContentWrapper(object folderId, Guid userIdOrGroupId, FilterType filterType) + private FolderContentWrapper ToFolderContentWrapper(string folderId, Guid userIdOrGroupId, FilterType filterType) { if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) { @@ -1568,7 +1568,7 @@ namespace ASC.Api.Documents startIndex); } - private FolderContentWrapper ToFolderContentWrapper(int folderId, Guid userIdOrGroupId, FilterType filterType) + private FolderContentWrapper ToFolderContentWrapper(int folderId, Guid userIdOrGroupId, FilterType filterType) { if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) { @@ -1823,7 +1823,7 @@ namespace ASC.Api.Documents /// Result file of operation. /// [DataMember(Name = "result")] - public FileWrapper File { get; set; } + public FileWrapper File { get; set; } /// /// Error during conversation. diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index 2bd56ba45e..20dfe2b797 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -58,7 +58,7 @@ namespace ASC.Files.Core.Data public GlobalStore GlobalStore { get; } public GlobalSpace GlobalSpace { get; } public GlobalFolder GlobalFolder { get; } - public IFolderDao FolderDao { get; } + public IDaoFactory DaoFactory { get; } public ChunkedUploadSessionHolder ChunkedUploadSessionHolder { get; } public FileDao( @@ -78,7 +78,7 @@ namespace ASC.Files.Core.Data GlobalStore globalStore, GlobalSpace globalSpace, GlobalFolder globalFolder, - IFolderDao folderDao, + IDaoFactory daoFactory, ChunkedUploadSessionHolder chunkedUploadSessionHolder) : base( dbContextManager, @@ -98,7 +98,7 @@ namespace ASC.Files.Core.Data GlobalStore = globalStore; GlobalSpace = globalSpace; GlobalFolder = globalFolder; - FolderDao = folderDao; + DaoFactory = daoFactory; ChunkedUploadSessionHolder = chunkedUploadSessionHolder; } @@ -687,7 +687,7 @@ namespace ASC.Files.Core.Data { f.FolderId = toFolderId; - if (GlobalFolder.GetFolderTrash(FolderDao).Equals(toFolderId)) + if (GlobalFolder.GetFolderTrash(DaoFactory).Equals(toFolderId)) { f.ModifiedBy = AuthContext.CurrentAccount.ID; f.ModifiedOn = DateTime.UtcNow; diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs index 8b6386fd62..c31650bae4 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs @@ -416,7 +416,191 @@ namespace ASC.Files.Core.Data public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - throw new NotImplementedException(); + if (parentFolder == null || parentFolder.ID == 0) + throw new ArgumentException("folderId"); + + var result = new List(); + + var monitorFolderIds = new object[] { parentFolder.ID }.AsEnumerable(); + + var getBaseSqlQuery = new Func>(() => + { + var fnResult = Query(FilesDbContext.Tag) + .Join(FilesDbContext.TagLink, r => r.Id, l => l.TagId, (tag, link) => new TagLinkData { Tag = tag, Link = link }) + .Where(r => r.Link.TenantId == r.Tag.TenantId) + .Where(r => r.Tag.Flag == TagType.New) + .Distinct(); + + if (subject != Guid.Empty) + { + fnResult = fnResult.Where(r => r.Tag.Owner == subject); + } + + return fnResult; + }); + + var tempTags = Enumerable.Empty(); + + if (parentFolder.FolderType == FolderType.SHARE) + { + var shareQuery = + new Func>(() => getBaseSqlQuery().Where( + r => FilesDbContext.Security + .Where(a => a.TenantId == r.Link.TenantId) + .Where(a => a.EntryId == r.Link.EntryId) + .Where(a => a.EntryType == r.Link.EntryType) + .Any())); + + var tmpShareFileTags = + shareQuery() + .Join(FilesDbContext.Files, r => r.Link.EntryId, f => f.Id.ToString(), (tagLink, file) => new { tagLink, file }) + .Where(r => r.file.TenantId == r.tagLink.Link.TenantId) + .Where(r => r.file.CreateBy != subject) + .Where(r => r.tagLink.Link.EntryType == FileEntryType.File) + .Select(r => new + { + r.tagLink, + root = FilesDbContext.Folders + .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) + .Where(x => x.folder.TenantId == r.file.TenantId) + .Where(x => x.tree.FolderId == r.file.FolderId) + .OrderByDescending(r => r.tree.Level) + .Select(r => r.folder) + .FirstOrDefault() + }) + .Where(r => r.root.FolderType == FolderType.USER) + .Select(r => r.tagLink); + + tempTags = tempTags.Concat(FromQuery(tmpShareFileTags)); + + + var tmpShareFolderTags = + shareQuery() + .Join(FilesDbContext.Folders, r => r.Link.EntryId, f => f.Id.ToString(), (tagLink, folder) => new { tagLink, folder }) + .Where(r => r.folder.TenantId == r.tagLink.Link.TenantId) + .Where(r => r.folder.CreateBy != subject) + .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) + .Select(r => new + { + r.tagLink, + root = FilesDbContext.Folders + .Join(FilesDbContext.Tree, a => a.Id, b => b.ParentId, (folder, tree) => new { folder, tree }) + .Where(x => x.folder.TenantId == r.folder.TenantId) + .Where(x => x.tree.FolderId == r.folder.ParentId) + .OrderByDescending(r => r.tree.Level) + .Select(r => r.folder) + .FirstOrDefault() + }) + .Where(r => r.root.FolderType == FolderType.USER) + .Select(r => r.tagLink); + + tempTags = tempTags.Concat(FromQuery(tmpShareFolderTags)); + + var tmpShareSboxTags = + shareQuery() + .Join(FilesDbContext.ThirdpartyIdMapping, r => r.Link.EntryId, r => r.HashId, (tagLink, mapping) => new { tagLink, mapping }) + .Where(r => r.mapping.TenantId == r.tagLink.Link.TenantId) + .Join(FilesDbContext.ThirdpartyAccount, r => r.mapping.TenantId, r => r.TenantId, (tagLinkMapping, account) => new { tagLinkMapping.tagLink, tagLinkMapping.mapping, account }) + .Where(r => r.account.UserId != subject) + .Where(r => r.account.FolderType == FolderType.USER) + .Where(r => + r.mapping.Id.StartsWith("sbox-" + r.account.Id) || + r.mapping.Id.StartsWith("box-" + r.account.Id) || + r.mapping.Id.StartsWith("dropbox-" + r.account.Id) || + r.mapping.Id.StartsWith("spoint-" + r.account.Id) || + r.mapping.Id.StartsWith("drive-" + r.account.Id) || + r.mapping.Id.StartsWith("onedrive-" + r.account.Id) + ) + .Select(r => r.tagLink); + + tempTags = tempTags.Concat(FromQuery(tmpShareSboxTags)); + } + else if (parentFolder.FolderType == FolderType.Projects) + { + var q = getBaseSqlQuery() + .Join(FilesDbContext.BunchObjects, r => r.Link.TenantId, r => r.TenantId, (tagLink, bunch) => new { tagLink, bunch }) + .Where(r => r.bunch.LeftNode == r.tagLink.Link.EntryId) + .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) + .Where(r => r.bunch.RightNode.StartsWith("projects/project/")) + .Select(r => r.tagLink); + tempTags = tempTags.Concat(FromQuery(q)); + } + + if (tempTags.Any()) + { + if (!deepSearch) return tempTags; + + monitorFolderIds = monitorFolderIds.Concat(tempTags.Where(x => x.EntryType == FileEntryType.Folder).Select(x => x.EntryId)); + result.AddRange(tempTags); + } + + var monitorFolderIdsInt = monitorFolderIds.Select(r => Convert.ToInt32(r)).ToList(); + var subFoldersSqlQuery = + FilesDbContext.Tree + .Where(r => monitorFolderIdsInt.Any(a => r.ParentId == a)); + + if (!deepSearch) + { + subFoldersSqlQuery = subFoldersSqlQuery.Where(r => r.Level == 1); + } + + monitorFolderIds = monitorFolderIds.Concat(subFoldersSqlQuery.Select(r => r.FolderId).ToList().ConvertAll(r => (object)r)); + + var monitorFolderIdsStrings = monitorFolderIds.Select(r => r.ToString()).ToList(); + + var newTagsForFolders = getBaseSqlQuery() + .Where(r => monitorFolderIdsStrings.Any(a => r.Link.EntryId == a)) + .Where(r => r.Link.EntryType == FileEntryType.Folder); + + result.AddRange(FromQuery(newTagsForFolders)); + + var where = (deepSearch ? monitorFolderIds.ToArray() : new object[] { parentFolder.ID }) + .Select(r => r.ToString()) + .ToList(); + + var newTagsForFiles = + getBaseSqlQuery() + .Join(FilesDbContext.Files, r => r.Link.EntryId, r => r.Id.ToString(), (tagLink, file) => new { tagLink, file }) + .Where(r => r.file.TenantId == r.tagLink.Link.TenantId) + .Where(r => where.Any(a => r.file.FolderId.ToString() == a)) + .Where(r => r.tagLink.Link.EntryType == FileEntryType.File) + .Select(r => r.tagLink); + + result.AddRange(FromQuery(newTagsForFiles)); + + if (parentFolder.FolderType == FolderType.USER || parentFolder.FolderType == FolderType.COMMON) + { + var folderType = parentFolder.FolderType; + + var querySelect = FilesDbContext.ThirdpartyAccount + .Where(r => r.TenantId == TenantID) + .Where(r => r.FolderType == folderType); + + if (folderType == FolderType.USER) + { + querySelect = querySelect.Where(r => r.UserId == subject); + } + + var folderIds = querySelect.Select(r => r.Id).ToList(); + var thirdpartyFolderIds = folderIds.ConvertAll(r => "sbox-" + r) + .Concat(folderIds.ConvertAll(r => $"box-{r}")) + .Concat(folderIds.ConvertAll(r => $"dropbox-{r}")) + .Concat(folderIds.ConvertAll(r => $"spoint-{r}")) + .Concat(folderIds.ConvertAll(r => $"drive-{r}")) + .Concat(folderIds.ConvertAll(r => $"onedrive-{r}")); + + var newTagsForSBox = getBaseSqlQuery() + .Join(FilesDbContext.ThirdpartyIdMapping, r => r.Link.EntryId, r => r.HashId, (tagLink, mapping) => new { tagLink, mapping }) + .Where(r => r.mapping.TenantId == r.tagLink.Link.TenantId) + .Where(r => thirdpartyFolderIds.Any(a => r.mapping.Id == a)) + .Where(r => r.tagLink.Tag.Owner == subject) + .Where(r => r.tagLink.Link.EntryType == FileEntryType.Folder) + .Select(r => r.tagLink); + + result.AddRange(FromQuery(newTagsForSBox)); + } + + return result; } protected List FromQuery(IQueryable dbFilesTags) @@ -429,7 +613,7 @@ namespace ASC.Files.Core.Data private Tag ToTag(TagLinkData r) { - var result = new Tag(r.Tag.Name, r.Tag.Flag, r.Tag.Owner, null, r.Link.TagCount) + var result = new Tag(r.Tag.Name, r.Tag.Flag, r.Tag.Owner, r.Link.TagCount) { EntryId = MappingID(r.Link.EntryId), EntryType = r.Link.EntryType, diff --git a/products/ASC.Files/Server/Core/Entries/Tag.cs b/products/ASC.Files/Server/Core/Entries/Tag.cs index b0f39c11a1..515ecf92be 100644 --- a/products/ASC.Files/Server/Core/Entries/Tag.cs +++ b/products/ASC.Files/Server/Core/Entries/Tag.cs @@ -60,23 +60,28 @@ namespace ASC.Files.Core } public Tag(string name, TagType type, Guid owner) - : this(name, type, owner, null, 0) + : this(name, type, owner, 0) { } - public Tag(string name, TagType type, Guid owner, FileEntry entry, int count) + public Tag(string name, TagType type, Guid owner, int count) { TagName = name; TagType = type; Owner = owner; Count = count; + } + + public Tag AddEntry(FileEntry entry) + { if (entry != null) { EntryId = entry.ID; EntryType = entry.FileEntryType; } - } + return this; + } public static Tag New(Guid owner, FileEntry entry) { @@ -85,13 +90,17 @@ namespace ASC.Files.Core public static Tag New(Guid owner, FileEntry entry, int count) { - return new Tag("new", TagType.New, owner, entry, count); + return new Tag("new", TagType.New, owner, count).AddEntry(entry); } public override bool Equals(object obj) { var f = obj as Tag; - return f != null && f.Id == Id && f.EntryType == EntryType && Equals(f.EntryId, EntryId); + return f != null && Equals(f); + } + public bool Equals(Tag f) + { + return f.Id == Id && f.EntryType == EntryType && Equals(f.EntryId, EntryId); } public override int GetHashCode() diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index c8494d5b94..072cd315dd 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -315,7 +315,7 @@ namespace ASC.Web.Files.Services.WCFService var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy); var response = new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StreamContent(serializer.ToXml(folderItems)) + Content = new StreamContent(serializer.ToXml(folderItems)) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return response; @@ -854,7 +854,7 @@ namespace ASC.Web.Files.Services.WCFService { if (tagLocked == null) { - tagLocked = new Tag("locked", TagType.Locked, AuthContext.CurrentAccount.ID, file, 0); + tagLocked = new Tag("locked", TagType.Locked, AuthContext.CurrentAccount.ID, 0).AddEntry(file); tagDao.SaveTags(tagLocked); } @@ -1046,7 +1046,7 @@ namespace ASC.Web.Files.Services.WCFService var response = new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StreamContent(serializer.ToXml(new ItemList>(result))) + Content = new StreamContent(serializer.ToXml(new ItemList>(result))) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return response; @@ -1157,7 +1157,7 @@ namespace ASC.Web.Files.Services.WCFService lostFolderType = lostProvider.RootFolderType; if (lostProvider.RootFolderType == FolderType.COMMON && !thirdPartyParams.Corporate) { - var lostFolder = folderDao.GetFolder((int)lostProvider.RootFolderId); + var lostFolder = folderDao.GetFolder((T)Convert.ChangeType(lostProvider.RootFolderId, typeof(T))); FileMarker.RemoveMarkAsNewForAll(lostFolder); } diff --git a/products/ASC.Files/Server/Helpers/Global.cs b/products/ASC.Files/Server/Helpers/Global.cs index c85ca571af..959fd362b0 100644 --- a/products/ASC.Files/Server/Helpers/Global.cs +++ b/products/ASC.Files/Server/Helpers/Global.cs @@ -511,6 +511,7 @@ namespace ASC.Web.Files.Classes public T GetFolderMy() => (T)Convert.ChangeType(FolderMy, typeof(T)); public T GetFolderCommon() => (T)Convert.ChangeType(FolderCommon, typeof(T)); public T GetFolderProjects() => (T)Convert.ChangeType(FolderProjects, typeof(T)); + public T GetFolderTrash() => (T)Convert.ChangeType(FolderTrash, typeof(T)); public void SetFolderMy(T val) { diff --git a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs index f9ecd40a7e..5286b1372f 100644 --- a/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Server/HttpHandlers/FileHandler.ashx.cs @@ -1000,7 +1000,7 @@ namespace ASC.Web.Files return; } - FileMarker.MarkAsNew(file); + FileMarker.MarkAsNew(file); if (responseMessage) { diff --git a/products/ASC.Files/Server/Model/FileEntryWrapper.cs b/products/ASC.Files/Server/Model/FileEntryWrapper.cs index 08de5e4996..f5a30bdee2 100644 --- a/products/ASC.Files/Server/Model/FileEntryWrapper.cs +++ b/products/ASC.Files/Server/Model/FileEntryWrapper.cs @@ -37,12 +37,12 @@ namespace ASC.Api.Documents /// /// [DataContract(Namespace = "")] - public abstract class FileEntryWrapper + public abstract class FileEntryWrapper { /// /// [DataMember] - public object Id { get; set; } + public T Id { get; set; } /// /// @@ -152,7 +152,7 @@ namespace ASC.Api.Documents EmployeeWraperHelper = employeeWraperHelper; } - protected internal T Get(FileEntry entry) where T : FileEntryWrapper, new() + protected internal T Get(FileEntry entry) where T : FileEntryWrapper, new() { return new T { diff --git a/products/ASC.Files/Server/Model/FileOperationWraper.cs b/products/ASC.Files/Server/Model/FileOperationWraper.cs index 1dc4ed05ac..905b3b45c6 100644 --- a/products/ASC.Files/Server/Model/FileOperationWraper.cs +++ b/products/ASC.Files/Server/Model/FileOperationWraper.cs @@ -40,7 +40,7 @@ namespace ASC.Api.Documents /// /// [DataContract(Name = "operation_result", Namespace = "")] - public class FileOperationWraper + public class FileOperationWraper { /// /// @@ -80,12 +80,12 @@ namespace ASC.Api.Documents /// /// [DataMember(Name = "files", IsRequired = true, EmitDefaultValue = true)] - public List Files { get; set; } + public List> Files { get; set; } /// /// [DataMember(Name = "folders", IsRequired = true, EmitDefaultValue = true)] - public List Folders { get; set; } + public List> Folders { get; set; } /// /// @@ -96,9 +96,9 @@ namespace ASC.Api.Documents /// /// /// - public static FileOperationWraper GetSample() + public static FileOperationWraper GetSample() { - return new FileOperationWraper + return new FileOperationWraper { Id = Guid.NewGuid().ToString(), OperationType = FileOperationType.Move, @@ -107,8 +107,8 @@ namespace ASC.Api.Documents //Result = "folder_1,file_1", Error = "", Processed = "1", - Files = new List { FileWrapper.GetSample() }, - Folders = new List { FolderWrapper.GetSample() } + Files = new List> { FileWrapper.GetSample() }, + Folders = new List> { FolderWrapper.GetSample() } }; } } @@ -132,9 +132,9 @@ namespace ASC.Api.Documents CommonLinkUtility = commonLinkUtility; } - public FileOperationWraper Get(FileOperationResult o) + public FileOperationWraper Get(FileOperationResult o) { - var result = new FileOperationWraper + var result = new FileOperationWraper { Id = o.Id, OperationType = o.OperationType, diff --git a/products/ASC.Files/Server/Model/FileWrapper.cs b/products/ASC.Files/Server/Model/FileWrapper.cs index 4e68a8a38f..a298f5edd8 100644 --- a/products/ASC.Files/Server/Model/FileWrapper.cs +++ b/products/ASC.Files/Server/Model/FileWrapper.cs @@ -46,12 +46,12 @@ namespace ASC.Api.Documents /// /// [DataContract(Name = "file", Namespace = "")] - public class FileWrapper : FileEntryWrapper + public class FileWrapper : FileEntryWrapper { /// /// [DataMember(EmitDefaultValue = false, IsRequired = false)] - public object FolderId { get; set; } + public T FolderId { get; set; } /// /// @@ -120,9 +120,9 @@ namespace ASC.Api.Documents /// /// /// - public static FileWrapper GetSample() + public static FileWrapper GetSample() { - return new FileWrapper + return new FileWrapper { Access = FileShare.ReadWrite, //Updated = ApiDateTime.GetSample(), @@ -175,9 +175,9 @@ namespace ASC.Api.Documents FileUtility = fileUtility; } - public FileWrapper Get(File file) + public FileWrapper Get(File file) { - var result = Get(file); + var result = Get, T>(file); result.FolderId = file.FolderID; if (file.RootFolderType == FolderType.USER && !Equals(file.RootFolderCreator, AuthContext.CurrentAccount.ID)) @@ -187,7 +187,7 @@ namespace ASC.Api.Documents var parentFolder = folderDao.GetFolder(file.FolderID); if (!FileSecurity.CanRead(parentFolder)) { - result.FolderId = GlobalFolderHelper.FolderShare; + result.FolderId = GlobalFolderHelper.GetFolderShare(); } } diff --git a/products/ASC.Files/Server/Model/FolderContentWrapper.cs b/products/ASC.Files/Server/Model/FolderContentWrapper.cs index 61fa258933..2e4a934227 100644 --- a/products/ASC.Files/Server/Model/FolderContentWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderContentWrapper.cs @@ -37,22 +37,22 @@ namespace ASC.Api.Documents /// /// [DataContract(Name = "content", Namespace = "")] - public class FolderContentWrapper + public class FolderContentWrapper { /// /// [DataMember(IsRequired = false, EmitDefaultValue = false)] - public List Files { get; set; } + public List> Files { get; set; } /// /// [DataMember(IsRequired = false, EmitDefaultValue = false)] - public List Folders { get; set; } + public List> Folders { get; set; } /// /// [DataMember(IsRequired = false, EmitDefaultValue = true)] - public FolderWrapper Current { get; set; } + public FolderWrapper Current { get; set; } /// /// @@ -86,13 +86,13 @@ namespace ASC.Api.Documents /// /// /// - public static FolderContentWrapper GetSample() + public static FolderContentWrapper GetSample() { - return new FolderContentWrapper + return new FolderContentWrapper { - Current = FolderWrapper.GetSample(), - Files = new List(new[] { FileWrapper.GetSample(), FileWrapper.GetSample() }), - Folders = new List(new[] { FolderWrapper.GetSample(), FolderWrapper.GetSample() }), + Current = FolderWrapper.GetSample(), + Files = new List>(new[] { FileWrapper.GetSample(), FileWrapper.GetSample() }), + Folders = new List>(new[] { FolderWrapper.GetSample(), FolderWrapper.GetSample() }), PathParts = new { key = "Key", @@ -119,9 +119,9 @@ namespace ASC.Api.Documents FolderWrapperHelper = folderWrapperHelper; } - public FolderContentWrapper Get(DataWrapper folderItems, int startIndex) + public FolderContentWrapper Get(DataWrapper folderItems, int startIndex) { - var result = new FolderContentWrapper + var result = new FolderContentWrapper { Files = folderItems.Entries.OfType>().Select(FileWrapperHelper.Get).ToList(), Folders = folderItems.Entries.OfType>().Select(FolderWrapperHelper.Get).ToList(), diff --git a/products/ASC.Files/Server/Model/FolderWrapper.cs b/products/ASC.Files/Server/Model/FolderWrapper.cs index 288a09768e..d8b46969d2 100644 --- a/products/ASC.Files/Server/Model/FolderWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderWrapper.cs @@ -41,12 +41,12 @@ namespace ASC.Api.Documents /// /// [DataContract(Name = "folder", Namespace = "")] - public class FolderWrapper : FileEntryWrapper + public class FolderWrapper : FileEntryWrapper { /// /// [DataMember(IsRequired = true, EmitDefaultValue = true)] - public object ParentId { get; set; } + public T ParentId { get; set; } /// /// @@ -73,9 +73,9 @@ namespace ASC.Api.Documents /// /// /// - public static FolderWrapper GetSample() + public static FolderWrapper GetSample() { - return new FolderWrapper + return new FolderWrapper { Access = FileShare.ReadWrite, //Updated = ApiDateTime.GetSample(), @@ -116,9 +116,9 @@ namespace ASC.Api.Documents GlobalFolderHelper = globalFolderHelper; } - public FolderWrapper Get(Folder folder) + public FolderWrapper Get(Folder folder) { - var result = Get(folder); + var result = Get, T>(folder); result.ParentId = folder.ParentFolderID; if (folder.RootFolderType == FolderType.USER && !Equals(folder.RootFolderCreator, AuthContext.CurrentAccount.ID)) @@ -128,7 +128,7 @@ namespace ASC.Api.Documents var folderDao = DaoFactory.GetFolderDao(); var parentFolder = folderDao.GetFolder(folder.ParentFolderID); if (!FileSecurity.CanRead(parentFolder)) - result.ParentId = GlobalFolderHelper.FolderShare; + result.ParentId = GlobalFolderHelper.GetFolderShare(); } result.FilesCount = folder.TotalFiles; diff --git a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs index bc1690208e..f13bc7e66b 100644 --- a/products/ASC.Files/Server/Services/DocumentService/Configuration.cs +++ b/products/ASC.Files/Server/Services/DocumentService/Configuration.cs @@ -58,8 +58,6 @@ using ASC.Web.Studio.Utility; using Microsoft.Extensions.DependencyInjection; -using File = ASC.Files.Core.File; - namespace ASC.Web.Files.Services.DocumentService { public enum EditorType diff --git a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs index 83c609b561..9cbcda3c7f 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileEntrySerializer.cs @@ -60,7 +60,7 @@ namespace ASC.Web.Files.Services.WCFService //} } - public System.IO.MemoryStream ToXml(object o) + public System.IO.MemoryStream ToXml(object o) { var result = new System.IO.MemoryStream(); if (o == null) @@ -85,7 +85,7 @@ namespace ASC.Web.Files.Services.WCFService //remove incorrect ns foreach (XmlNode entry in xml.SelectNodes("//entry")) { - var nsattr = entry.Attributes.Cast().FirstOrDefault(a => a.Value == typeof(FileEntry).Name); + var nsattr = entry.Attributes.Cast().FirstOrDefault(a => a.Value == typeof(FileEntry<>).Name); if (nsattr != null) { foreach (XmlAttribute a in entry.Attributes) diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index 404a9dceab..97ba0bd12a 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -111,7 +111,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations MoveOrCopyFolders(scope, Folders, toFolder, _copy); MoveOrCopyFiles(scope, Files, toFolder, _copy); - _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); + _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); } private void MoveOrCopyFolders(IServiceScope scope, List folderIds, Folder toFolder, bool copy) diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index f9ec4452e7..997471d667 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -600,7 +600,7 @@ namespace ASC.Web.Files.Utils folder.ProviderId = providerInfo.ID; folder.ProviderKey = providerInfo.ProviderKey; folder.RootFolderCreator = providerInfo.Owner; - folder.RootFolderId = providerInfo.RootFolderId; + folder.RootFolderId = (T)Convert.ChangeType(providerInfo.RootFolderId, typeof(T)); folder.RootFolderType = providerInfo.RootFolderType; folder.Shareable = false; folder.Title = providerInfo.CustomerTitle; diff --git a/products/ASC.Files/Server/Utils/FileConverter.cs b/products/ASC.Files/Server/Utils/FileConverter.cs index 5ae86affe7..65a305db8d 100644 --- a/products/ASC.Files/Server/Utils/FileConverter.cs +++ b/products/ASC.Files/Server/Utils/FileConverter.cs @@ -61,16 +61,353 @@ using SecurityContext = ASC.Core.SecurityContext; namespace ASC.Web.Files.Utils { - public class FileConverter + internal class FileConverterQueue { - private static readonly object locker = new object(); - private static readonly IDictionary, ConvertFileOperationResult> conversionQueue = new Dictionary, ConvertFileOperationResult>(new FileComparer()); + private readonly object singleThread = new object(); + private readonly IDictionary, ConvertFileOperationResult> conversionQueue; + private readonly Timer timer; + private readonly object locker; private readonly ICache cache; - - private static Timer timer; - private static readonly object singleThread = new object(); private const int TIMER_PERIOD = 500; + public IServiceProvider ServiceProvider { get; } + + public FileConverterQueue(IServiceProvider ServiceProvider) + { + conversionQueue = new Dictionary, ConvertFileOperationResult>(new FileComparer()); + timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); + locker = new object(); + this.ServiceProvider = ServiceProvider; + cache = AscCache.Memory; + } + + public void Add(File file, string password, int tenantId, IAccount account, bool deleteAfter, string url) + { + lock (locker) + { + if (conversionQueue.ContainsKey(file)) + { + return; + } + + var queueResult = new ConvertFileOperationResult + { + Source = string.Format("{{\"id\":\"{0}\", \"version\":\"{1}\"}}", file.ID, file.Version), + OperationType = FileOperationType.Convert, + Error = string.Empty, + Progress = 0, + Result = string.Empty, + Processed = "", + Id = string.Empty, + TenantId = tenantId, + Account = account, + Delete = deleteAfter, + StartDateTime = DateTime.Now, + Url = url, + Password = password + }; + conversionQueue.Add(file, queueResult); + cache.Insert(GetKey(file), queueResult, TimeSpan.FromMinutes(10)); + + timer.Change(0, Timeout.Infinite); + } + } + + public ConvertFileOperationResult GetStatus(KeyValuePair, bool> pair, FileSecurity fileSecurity) + { + var file = pair.Key; + var key = GetKey(file); + var operation = cache.Get(key); + if (operation != null && (pair.Value || fileSecurity.CanRead(file))) + { + lock (locker) + { + if (operation.Progress == 100) + { + conversionQueue.Remove(file); + cache.Remove(key); + } + return operation; + } + } + return null; + } + + public bool IsConverting(File file) + { + var result = cache.Get(GetKey(file)); + return result != null && result.Progress != 100 && string.IsNullOrEmpty(result.Error); + } + + private void CheckConvertFilesStatus(object _) + { + if (Monitor.TryEnter(singleThread)) + { + using var scope = ServiceProvider.CreateScope(); + var logger = scope.ServiceProvider.GetService>().CurrentValue; + var tenantManager = scope.ServiceProvider.GetService(); + var userManager = scope.ServiceProvider.GetService(); + var securityContext = scope.ServiceProvider.GetService(); + var daoFactory = scope.ServiceProvider.GetService(); + var FileSecurity = scope.ServiceProvider.GetService(); + var PathProvider = scope.ServiceProvider.GetService(); + var SetupInfo = scope.ServiceProvider.GetService(); + var FileUtility = scope.ServiceProvider.GetService(); + var DocumentServiceHelper = scope.ServiceProvider.GetService(); + var DocumentServiceConnector = scope.ServiceProvider.GetService(); + var EntryManager = scope.ServiceProvider.GetService(); + var FileConverter = scope.ServiceProvider.GetService(); + + try + { + var filesIsConverting = new List>(); + lock (locker) + { + timer.Change(Timeout.Infinite, Timeout.Infinite); + + conversionQueue.Where(x => !string.IsNullOrEmpty(x.Value.Processed) + && (x.Value.Progress == 100 && DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(1) || + DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(10))) + .ToList() + .ForEach(x => + { + conversionQueue.Remove(x); + cache.Remove(GetKey(x.Key)); + }); + + logger.DebugFormat("Run CheckConvertFilesStatus: count {0}", conversionQueue.Count); + + if (conversionQueue.Count == 0) + { + return; + } + + filesIsConverting = conversionQueue + .Where(x => string.IsNullOrEmpty(x.Value.Processed)) + .Select(x => x.Key) + .ToList(); + } + + var fileSecurity = FileSecurity; + foreach (var file in filesIsConverting) + { + var fileUri = file.ID.ToString(); + string convertedFileUrl; + int operationResultProgress; + + try + { + int tenantId; + IAccount account; + string password; + + lock (locker) + { + if (!conversionQueue.Keys.Contains(file)) continue; + + var operationResult = conversionQueue[file]; + if (!string.IsNullOrEmpty(operationResult.Processed)) continue; + + operationResult.Processed = "1"; + tenantId = operationResult.TenantId; + account = operationResult.Account; + password = operationResult.Password; + + //if (HttpContext.Current == null && !WorkContext.IsMono) + //{ + // HttpContext.Current = new HttpContext( + // new HttpRequest("hack", operationResult.Url, string.Empty), + // new HttpResponse(new StringWriter())); + //} + + cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); + } + + tenantManager.SetCurrentTenant(tenantId); + securityContext.AuthenticateMe(account); + + var user = userManager.GetUsers(account.ID); + var culture = string.IsNullOrEmpty(user.CultureName) ? tenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName); + Thread.CurrentThread.CurrentCulture = culture; + Thread.CurrentThread.CurrentUICulture = culture; + + if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) + { + //No rights in CRM after upload before attach + throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); + } + if (file.ContentLength > SetupInfo.AvailableFileSize) + { + throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); + } + + fileUri = PathProvider.GetFileStreamUrl(file); + + var toExtension = FileUtility.GetInternalExtension(file.Title); + var fileExtension = file.ConvertedExtension; + var docKey = DocumentServiceHelper.GetDocKey(file); + + fileUri = DocumentServiceConnector.ReplaceCommunityAdress(fileUri); + operationResultProgress = DocumentServiceConnector.GetConvertedUri(fileUri, fileExtension, toExtension, docKey, password, true, out convertedFileUrl); + } + catch (Exception exception) + { + var password = exception.InnerException != null + && (exception.InnerException is DocumentService.DocumentServiceException documentServiceException) + && documentServiceException.Code == DocumentService.DocumentServiceException.ErrorCode.ConvertPassword; + + logger.Error(string.Format("Error convert {0} with url {1}", file.ID, fileUri), exception); + lock (locker) + { + if (conversionQueue.Keys.Contains(file)) + { + var operationResult = conversionQueue[file]; + if (operationResult.Delete) + { + conversionQueue.Remove(file); + cache.Remove(GetKey(file)); + } + else + { + operationResult.Progress = 100; + operationResult.StopDateTime = DateTime.UtcNow; + operationResult.Error = exception.Message; + if (password) operationResult.Result = "password"; + cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); + } + } + } + continue; + } + + operationResultProgress = Math.Min(operationResultProgress, 100); + if (operationResultProgress < 100) + { + lock (locker) + { + if (conversionQueue.Keys.Contains(file)) + { + var operationResult = conversionQueue[file]; + + if (DateTime.Now - operationResult.StartDateTime > TimeSpan.FromMinutes(10)) + { + operationResult.StopDateTime = DateTime.UtcNow; + operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout; + logger.ErrorFormat("CheckConvertFilesStatus timeout: {0} ({1})", file.ID, file.ContentLengthString); + } + else + { + operationResult.Processed = ""; + } + operationResult.Progress = operationResultProgress; + cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); + } + } + + logger.Debug("CheckConvertFilesStatus iteration continue"); + continue; + } + + File newFile = null; + var operationResultError = string.Empty; + + try + { + newFile = FileConverter.SaveConvertedFile(file, convertedFileUrl); + } + catch (Exception e) + { + operationResultError = e.Message; + + logger.ErrorFormat("{0} ConvertUrl: {1} fromUrl: {2}: {3}", operationResultError, convertedFileUrl, fileUri, e); + continue; + } + finally + { + lock (locker) + { + if (conversionQueue.Keys.Contains(file)) + { + var operationResult = conversionQueue[file]; + if (operationResult.Delete) + { + conversionQueue.Remove(file); + cache.Remove(GetKey(file)); + } + else + { + if (newFile != null) + { + var folderDao = daoFactory.GetFolderDao(); + var folder = folderDao.GetFolder(newFile.FolderID); + var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; + operationResult.Result = FileJsonSerializer(EntryManager, newFile, folderTitle); + } + + operationResult.Progress = 100; + operationResult.StopDateTime = DateTime.UtcNow; + operationResult.Processed = "1"; + if (!string.IsNullOrEmpty(operationResultError)) + { + operationResult.Error = operationResultError; + } + cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); + } + } + } + } + + logger.Debug("CheckConvertFilesStatus iteration end"); + } + + lock (locker) + { + timer.Change(TIMER_PERIOD, TIMER_PERIOD); + } + } + catch (Exception exception) + { + logger.Error(exception.Message, exception); + lock (locker) + { + timer.Change(Timeout.Infinite, Timeout.Infinite); + } + } + finally + { + Monitor.Exit(singleThread); + } + } + } + + private string GetKey(File f) + { + return string.Format("fileConvertation-{0}", f.ID); + } + + private string FileJsonSerializer(EntryManager EntryManager, File file, string folderTitle) + { + if (file == null) return string.Empty; + + EntryManager.SetFileStatus(file); + return + string.Format("{{ \"id\": \"{0}\"," + + " \"title\": \"{1}\"," + + " \"version\": \"{2}\"," + + " \"folderId\": \"{3}\"," + + " \"folderTitle\": \"{4}\"," + + " \"fileXml\": \"{5}\" }}", + file.ID, + file.Title, + file.Version, + file.FolderID, + folderTitle ?? "", + File.Serialize(file).Replace('"', '\'')); + } + } + + public class FileConverter + { public FileUtility FileUtility { get; } public FilesLinkUtility FilesLinkUtility { get; } public IDaoFactory DaoFactory { get; } @@ -89,7 +426,6 @@ namespace ASC.Web.Files.Utils public DocumentServiceConnector DocumentServiceConnector { get; } public IServiceProvider ServiceProvider { get; } public IHttpContextAccessor HttpContextAccesor { get; } - public ILog Logger { get; } public FileConverter( FileUtility fileUtility, @@ -128,8 +464,6 @@ namespace ASC.Web.Files.Utils DocumentServiceHelper = documentServiceHelper; DocumentServiceConnector = documentServiceConnector; ServiceProvider = serviceProvider; - Logger = options.CurrentValue; - cache = AscCache.Memory; } public FileConverter( FileUtility fileUtility, @@ -269,42 +603,7 @@ namespace ASC.Web.Files.Utils } FileMarker.RemoveMarkAsNew(file); - - lock (locker) - { - if (conversionQueue.ContainsKey(file)) - { - return; - } - - var queueResult = new ConvertFileOperationResult - { - Source = string.Format("{{\"id\":\"{0}\", \"version\":\"{1}\"}}", file.ID, file.Version), - OperationType = FileOperationType.Convert, - Error = string.Empty, - Progress = 0, - Result = string.Empty, - Processed = "", - Id = string.Empty, - TenantId = TenantManager.GetCurrentTenant().TenantId, - Account = AuthContext.CurrentAccount, - Delete = deleteAfter, - StartDateTime = DateTime.Now, - Url = HttpContextAccesor?.HttpContext != null ? HttpContextAccesor.HttpContext.Request.GetUrlRewriter().ToString() : null, - Password = password - }; - conversionQueue.Add(file, queueResult); - cache.Insert(GetKey(file), queueResult, TimeSpan.FromMinutes(10)); - - if (timer == null) - { - timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite); - } - else - { - timer.Change(0, Timeout.Infinite); - } - } + GetFileConverter().Add(file, password, TenantManager.GetCurrentTenant().TenantId, AuthContext.CurrentAccount, deleteAfter, HttpContextAccesor?.HttpContext != null ? HttpContextAccesor.HttpContext.Request.GetUrlRewriter().ToString() : null); } public bool IsConverting(File file) @@ -313,289 +612,26 @@ namespace ASC.Web.Files.Utils { return false; } - var result = cache.Get(GetKey(file)); - return result != null && result.Progress != 100 && string.IsNullOrEmpty(result.Error); + + return GetFileConverter().IsConverting(file); } public IEnumerable GetStatus(IEnumerable, bool>> filesPair) { - var fileSecurity = FileSecurity; var result = new List(); foreach (var pair in filesPair) { - var file = pair.Key; - var key = GetKey(file); - var operation = cache.Get(key); - if (operation != null && (pair.Value || fileSecurity.CanRead(file))) + var r = GetFileConverter().GetStatus(pair, FileSecurity); + + if (r != null) { - result.Add(operation); - lock (locker) - { - if (operation.Progress == 100) - { - conversionQueue.Remove(file); - cache.Remove(key); - } - } + result.Add(r); } } return result; } - private string FileJsonSerializer(File file, string folderTitle) - { - if (file == null) return string.Empty; - - EntryManager.SetFileStatus(file); - return - string.Format("{{ \"id\": \"{0}\"," + - " \"title\": \"{1}\"," + - " \"version\": \"{2}\"," + - " \"folderId\": \"{3}\"," + - " \"folderTitle\": \"{4}\"," + - " \"fileXml\": \"{5}\" }}", - file.ID, - file.Title, - file.Version, - file.FolderID, - folderTitle ?? "", - File.Serialize(file).Replace('"', '\'')); - } - - private void CheckConvertFilesStatus(object _) - { - if (Monitor.TryEnter(singleThread)) - { - using var scope = ServiceProvider.CreateScope(); - var logger = scope.ServiceProvider.GetService>().CurrentValue; - var tenantManager = scope.ServiceProvider.GetService(); - var userManager = scope.ServiceProvider.GetService(); - var securityContext = scope.ServiceProvider.GetService(); - var daoFactory = scope.ServiceProvider.GetService(); - - try - { - var filesIsConverting = new List>(); - lock (locker) - { - timer.Change(Timeout.Infinite, Timeout.Infinite); - - conversionQueue.Where(x => !string.IsNullOrEmpty(x.Value.Processed) - && (x.Value.Progress == 100 && DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(1) || - DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(10))) - .ToList() - .ForEach(x => - { - conversionQueue.Remove(x); - cache.Remove(GetKey(x.Key)); - }); - - logger.DebugFormat("Run CheckConvertFilesStatus: count {0}", conversionQueue.Count); - - if (conversionQueue.Count == 0) - { - return; - } - - filesIsConverting = conversionQueue - .Where(x => string.IsNullOrEmpty(x.Value.Processed)) - .Select(x => x.Key) - .ToList(); - } - - var fileSecurity = FileSecurity; - foreach (var file in filesIsConverting) - { - var fileUri = file.ID.ToString(); - string convertedFileUrl; - int operationResultProgress; - - try - { - int tenantId; - IAccount account; - string password; - - lock (locker) - { - if (!conversionQueue.Keys.Contains(file)) continue; - - var operationResult = conversionQueue[file]; - if (!string.IsNullOrEmpty(operationResult.Processed)) continue; - - operationResult.Processed = "1"; - tenantId = operationResult.TenantId; - account = operationResult.Account; - password = operationResult.Password; - - //if (HttpContext.Current == null && !WorkContext.IsMono) - //{ - // HttpContext.Current = new HttpContext( - // new HttpRequest("hack", operationResult.Url, string.Empty), - // new HttpResponse(new StringWriter())); - //} - - cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); - } - - tenantManager.SetCurrentTenant(tenantId); - securityContext.AuthenticateMe(account); - - var user = userManager.GetUsers(account.ID); - var culture = string.IsNullOrEmpty(user.CultureName) ? TenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName); - Thread.CurrentThread.CurrentCulture = culture; - Thread.CurrentThread.CurrentUICulture = culture; - - if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH) - { - //No rights in CRM after upload before attach - throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile); - } - if (file.ContentLength > SetupInfo.AvailableFileSize) - { - throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); - } - - fileUri = PathProvider.GetFileStreamUrl(file); - - var toExtension = FileUtility.GetInternalExtension(file.Title); - var fileExtension = file.ConvertedExtension; - var docKey = DocumentServiceHelper.GetDocKey(file); - - fileUri = DocumentServiceConnector.ReplaceCommunityAdress(fileUri); - operationResultProgress = DocumentServiceConnector.GetConvertedUri(fileUri, fileExtension, toExtension, docKey, password, true, out convertedFileUrl); - } - catch (Exception exception) - { - var password = exception.InnerException != null - && (exception.InnerException is DocumentService.DocumentServiceException documentServiceException) - && documentServiceException.Code == DocumentService.DocumentServiceException.ErrorCode.ConvertPassword; - - logger.Error(string.Format("Error convert {0} with url {1}", file.ID, fileUri), exception); - lock (locker) - { - if (conversionQueue.Keys.Contains(file)) - { - var operationResult = conversionQueue[file]; - if (operationResult.Delete) - { - conversionQueue.Remove(file); - cache.Remove(GetKey(file)); - } - else - { - operationResult.Progress = 100; - operationResult.StopDateTime = DateTime.UtcNow; - operationResult.Error = exception.Message; - if (password) operationResult.Result = "password"; - cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); - } - } - } - continue; - } - - operationResultProgress = Math.Min(operationResultProgress, 100); - if (operationResultProgress < 100) - { - lock (locker) - { - if (conversionQueue.Keys.Contains(file)) - { - var operationResult = conversionQueue[file]; - - if (DateTime.Now - operationResult.StartDateTime > TimeSpan.FromMinutes(10)) - { - operationResult.StopDateTime = DateTime.UtcNow; - operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout; - logger.ErrorFormat("CheckConvertFilesStatus timeout: {0} ({1})", file.ID, file.ContentLengthString); - } - else - { - operationResult.Processed = ""; - } - operationResult.Progress = operationResultProgress; - cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); - } - } - - logger.Debug("CheckConvertFilesStatus iteration continue"); - continue; - } - - File newFile = null; - var operationResultError = string.Empty; - - try - { - newFile = SaveConvertedFile(file, convertedFileUrl); - } - catch (Exception e) - { - operationResultError = e.Message; - - logger.ErrorFormat("{0} ConvertUrl: {1} fromUrl: {2}: {3}", operationResultError, convertedFileUrl, fileUri, e); - continue; - } - finally - { - lock (locker) - { - if (conversionQueue.Keys.Contains(file)) - { - var operationResult = conversionQueue[file]; - if (operationResult.Delete) - { - conversionQueue.Remove(file); - cache.Remove(GetKey(file)); - } - else - { - if (newFile != null) - { - var folderDao = daoFactory.GetFolderDao(); - var folder = folderDao.GetFolder(newFile.FolderID); - var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null; - operationResult.Result = FileJsonSerializer(newFile, folderTitle); - } - - operationResult.Progress = 100; - operationResult.StopDateTime = DateTime.UtcNow; - operationResult.Processed = "1"; - if (!string.IsNullOrEmpty(operationResultError)) - { - operationResult.Error = operationResultError; - } - cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10)); - } - } - } - } - - logger.Debug("CheckConvertFilesStatus iteration end"); - } - - lock (locker) - { - timer.Change(TIMER_PERIOD, TIMER_PERIOD); - } - } - catch (Exception exception) - { - logger.Error(exception.Message, exception); - lock (locker) - { - timer.Change(Timeout.Infinite, Timeout.Infinite); - } - } - finally - { - Monitor.Exit(singleThread); - } - } - } - - private File SaveConvertedFile(File file, string convertedFileUrl) + public File SaveConvertedFile(File file, string convertedFileUrl) { var fileSecurity = FileSecurity; var fileDao = DaoFactory.GetFileDao(); @@ -681,7 +717,7 @@ namespace ASC.Web.Files.Utils } FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title); - FileMarker.MarkAsNew(newFile); + FileMarker.MarkAsNew(newFile); var tagDao = DaoFactory.GetTagDao(); var tags = tagDao.GetTags(file.ID, FileEntryType.File, TagType.System).ToList(); @@ -694,36 +730,32 @@ namespace ASC.Web.Files.Utils return newFile; } - private static string GetKey(File f) + private FileConverterQueue GetFileConverter() => ServiceProvider.GetService>(); + } + + internal class FileComparer : IEqualityComparer> + { + public bool Equals(File x, File y) { - return string.Format("fileConvertation-{0}", f.ID); + return x != null && y != null && Equals(x.ID, y.ID) && x.Version == y.Version; } - - private class FileComparer : IEqualityComparer> + public int GetHashCode(File obj) { - public bool Equals(File x, File y) - { - return x != null && y != null && Equals(x.ID, y.ID) && x.Version == y.Version; - } - - public int GetHashCode(File obj) - { - return obj.ID.GetHashCode() + obj.Version.GetHashCode(); - } + return obj.ID.GetHashCode() + obj.Version.GetHashCode(); } + } - [DataContract(Name = "operation_result", Namespace = "")] - private class ConvertFileOperationResult : FileOperationResult - { - public DateTime StartDateTime { get; set; } - public DateTime StopDateTime { get; set; } - public int TenantId { get; set; } - public IAccount Account { get; set; } - public bool Delete { get; set; } - public string Url { get; set; } - public string Password { get; set; } - } + [DataContract(Name = "operation_result", Namespace = "")] + internal class ConvertFileOperationResult : FileOperationResult + { + public DateTime StartDateTime { get; set; } + public DateTime StopDateTime { get; set; } + public int TenantId { get; set; } + public IAccount Account { get; set; } + public bool Delete { get; set; } + public string Url { get; set; } + public string Password { get; set; } } public static class FileConverterExtension @@ -731,6 +763,8 @@ namespace ASC.Web.Files.Utils public static DIHelper AddFileConverterService(this DIHelper services) { services.TryAddScoped(); + services.TryAddSingleton>(); + services.TryAddSingleton>(); return services .AddFilesLinkUtilityService() .AddFileUtilityService() diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index 6c9111d9c7..df202df218 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -46,18 +46,41 @@ using Microsoft.Extensions.Options; namespace ASC.Web.Files.Utils { - public class FileMarkerHelper + + public class FileMarkerHelper { private IServiceProvider ServiceProvider { get; } public ILog Log { get; } - public FileMarkerHelper(IServiceProvider serviceProvider, IOptionsMonitor optionsMonitor) + public object Locker { get; set; } + public WorkerQueue> Tasks { get; set; } + + public FileMarkerHelper( + IServiceProvider serviceProvider, + IOptionsMonitor optionsMonitor, + WorkerQueueOptionsManager> workerQueueOptionsManager) { ServiceProvider = serviceProvider; Log = optionsMonitor.CurrentValue; + Locker = new object(); + Tasks = workerQueueOptionsManager.Value; } - internal void ExecMarkFileAsNew(AsyncTaskData obj) + internal void Add(AsyncTaskData taskData) + { + + lock (Locker) + { + Tasks.Add(taskData); + + if (!Tasks.IsStarted) + { + Tasks.Start(ExecMarkFileAsNew); + } + } + } + + private void ExecMarkFileAsNew(AsyncTaskData obj) { try { @@ -70,13 +93,10 @@ namespace ASC.Web.Files.Utils Log.Error(e); } } - } public class FileMarker { - private static readonly object locker = new object(); - private readonly WorkerQueue> tasks; private readonly ICache cache; private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}"; @@ -89,7 +109,6 @@ namespace ASC.Web.Files.Utils public CoreBaseSettings CoreBaseSettings { get; } public AuthContext AuthContext { get; } public IServiceProvider ServiceProvider { get; } - public FileMarkerHelper FileMarkerHelper { get; } public FileMarker( TenantManager tenantManager, @@ -99,9 +118,7 @@ namespace ASC.Web.Files.Utils FileSecurity fileSecurity, CoreBaseSettings coreBaseSettings, AuthContext authContext, - IServiceProvider serviceProvider, - WorkerQueueOptionsManager> workerQueueOptionsManager, - FileMarkerHelper fileMarkerHelper) + IServiceProvider serviceProvider) { TenantManager = tenantManager; UserManager = userManager; @@ -111,9 +128,7 @@ namespace ASC.Web.Files.Utils CoreBaseSettings = coreBaseSettings; AuthContext = authContext; ServiceProvider = serviceProvider; - FileMarkerHelper = fileMarkerHelper; cache = AscCache.Memory; - tasks = workerQueueOptionsManager.Value; } internal void ExecMarkFileAsNew(AsyncTaskData obj) @@ -224,7 +239,7 @@ namespace ASC.Web.Files.Utils if (obj.FileEntry.ProviderEntry) { - var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); + var commonFolder = folderDao.GetFolder(GlobalFolder.GetFolderCommon(this, DaoFactory)); userIDs.ForEach(userID => { if (userEntriesData.ContainsKey(userID)) @@ -304,13 +319,7 @@ namespace ASC.Web.Files.Utils taskData.UserIDs = projectTeam; } - lock (locker) - { - tasks.Add(taskData); - - if (!tasks.IsStarted) - tasks.Start(FileMarkerHelper.ExecMarkFileAsNew); - } + ServiceProvider.GetService>().Add(taskData); } public void RemoveMarkAsNew(FileEntry fileEntry, Guid userID = default) @@ -349,7 +358,7 @@ namespace ASC.Web.Files.Utils { var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder); - var providerFolderTags = folderTags.Select(tag => new KeyValuePair>(tag, folderDao.GetFolder(tag.EntryId))) + var providerFolderTags = folderTags.Select(tag => new KeyValuePair>(tag, folderDao.GetFolder((T)tag.EntryId))) .Where(pair => pair.Value != null && pair.Value.ProviderEntry).ToList(); foreach (var providerFolderTag in providerFolderTags) @@ -378,9 +387,9 @@ namespace ASC.Web.Files.Utils else if (rootFolder.RootFolderType == FolderType.COMMON) { if (rootFolder.ProviderEntry) - cacheFolderId = rootFolderId = GlobalFolder.GetFolderCommon(this, DaoFactory); + cacheFolderId = rootFolderId = GlobalFolder.GetFolderCommon(this, DaoFactory); else - cacheFolderId = GlobalFolder.GetFolderCommon(this, DaoFactory); + cacheFolderId = GlobalFolder.GetFolderCommon(this, DaoFactory); } else if (rootFolder.RootFolderType == FolderType.USER) { @@ -450,8 +459,8 @@ namespace ASC.Web.Files.Utils { var rootIds = new List { - GlobalFolder.GetFolderMy(this, DaoFactory), - GlobalFolder.GetFolderCommon(this, DaoFactory), + GlobalFolder.GetFolderMy(this, DaoFactory), + GlobalFolder.GetFolderCommon(this, DaoFactory), GlobalFolder.GetFolderShare(DaoFactory), GlobalFolder.GetFolderProjects(DaoFactory) }; @@ -727,7 +736,6 @@ namespace ASC.Web.Files.Utils { public static DIHelper AddFileMarkerService(this DIHelper services) { - return services .AddFileMarkerService() .AddFileMarkerService() @@ -739,7 +747,7 @@ namespace ASC.Web.Files.Utils _ = services .TryAddTransient>() .TryAddScoped() - .TryAddSingleton() + .TryAddSingleton>() .TryAddSingleton>>() .TryAddSingleton>>() .AddSingleton>>, ConfigureWorkerQueue>>(); From 3f4ad15b46a81ca44310cd046f422f09b18f6d7e Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 6 Mar 2020 16:17:17 +0300 Subject: [PATCH 07/30] Files: fropbox --- .../ASC.Core.Common/Configuration/Consumer.cs | 25 +- .../LoginProviders/BaseLoginProvider.cs | 3 +- .../LoginProviders/BitlyLoginProvider.cs | 14 +- .../LoginProviders/BoxLoginProvider.cs | 11 +- .../LoginProviders/DocuSignLoginProvider.cs | 8 +- .../LoginProviders/DropboxLoginProvider.cs | 10 +- .../LoginProviders/FacebookLoginProvider.cs | 3 +- .../LoginProviders/GoogleLoginProvider.cs | 3 +- .../LoginProviders/GosUslugiLoginProvider.cs | 3 +- .../LoginProviders/LinkedInLoginProvider.cs | 3 +- .../LoginProviders/MailRuLoginProvider.cs | 3 +- .../LoginProviders/OneDriveLoginProvider.cs | 8 +- .../LoginProviders/VKLoginProvider.cs | 3 +- .../LoginProviders/WordpressLoginProvider.cs | 3 +- .../LoginProviders/YahooLoginProvider.cs | 3 +- .../LoginProviders/YandexLoginProvider.cs | 3 +- products/ASC.Files/Server/ASC.Files.csproj | 13 + .../Server/Controllers/FilesController.cs | 26 +- .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 5 +- .../Core/EF/DbFilesThirdpartyAccount.cs | 10 +- .../Server/Core/FileStorageService.cs | 12 +- .../Thirdparty/CachedProviderAccountDao.cs | 136 ++++ .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 435 +++++++++++++ .../Thirdparty/Dropbox/DropboxDaoSelector.cs | 149 +++++ .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 596 ++++++++++++++++++ .../Thirdparty/Dropbox/DropboxFolderDao.cs | 415 ++++++++++++ .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 282 +++++++++ .../Thirdparty/Dropbox/DropboxSecurityDao.cs | 99 +++ .../Core/Thirdparty/Dropbox/DropboxStorage.cs | 219 +++++++ .../Core/Thirdparty/Dropbox/DropboxTagDao.cs | 182 ++++++ .../Server/Core/Thirdparty/IDaoSelector.cs | 42 ++ .../Core/Thirdparty/ProviderAccountDao.cs | 579 +++++++++++++++++ .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 251 ++++++++ .../Core/Thirdparty/RegexDaoSelectorBase.cs | 122 ++++ .../Server/Helpers/DocuSignHelper.cs | 25 +- .../ASC.Files/Server/Helpers/EasyBibHelper.cs | 3 +- .../Server/Helpers/ThirdpartyConfiguration.cs | 31 +- .../ASC.Files/Server/ThirdPartyApp/BoxApp.cs | 3 +- .../Server/ThirdPartyApp/GoogleDriveApp.cs | 3 +- .../Server/proto/DropboxCacheItem.proto | 10 + .../proto/ProviderAccountCacheItem.proto | 7 + web/ASC.Web.Core/Jabber/FireBase.cs | 8 +- web/ASC.Web.Core/Sms/SmsProvider.cs | 18 +- 43 files changed, 3633 insertions(+), 154 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxStorage.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs create mode 100644 products/ASC.Files/Server/proto/DropboxCacheItem.proto create mode 100644 products/ASC.Files/Server/proto/ProviderAccountCacheItem.proto diff --git a/common/ASC.Core.Common/Configuration/Consumer.cs b/common/ASC.Core.Common/Configuration/Consumer.cs index f689ce400f..71466f2f46 100644 --- a/common/ASC.Core.Common/Configuration/Consumer.cs +++ b/common/ASC.Core.Common/Configuration/Consumer.cs @@ -82,7 +82,7 @@ namespace ASC.Core.Common.Configuration public TenantManager TenantManager { get; set; } public CoreBaseSettings CoreBaseSettings { get; set; } public CoreSettings CoreSettings { get; set; } - public ConsumerFactory ConsumerFactory { get; } + public ConsumerFactory ConsumerFactory { get; set; } public IConfiguration Configuration { get; } public ICacheNotify Cache { get; } @@ -106,14 +106,12 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache) : this() { TenantManager = tenantManager; CoreBaseSettings = coreBaseSettings; CoreSettings = coreSettings; - ConsumerFactory = consumerFactory; Configuration = configuration; Cache = cache; OnlyDefault = configuration["core:default-consumers"] == "true"; @@ -125,11 +123,10 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary additional) - : this(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache) + : this(tenantManager, coreBaseSettings, coreSettings, configuration, cache) { Name = name; Order = order; @@ -141,11 +138,10 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional) - : this(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache) + : this(tenantManager, coreBaseSettings, coreSettings, configuration, cache) { Name = name; Order = order; @@ -303,10 +299,9 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache) { } @@ -315,11 +310,10 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary additional) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, additional) { Init(additional); } @@ -328,11 +322,10 @@ namespace ASC.Core.Common.Configuration TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { Init(additional); } @@ -368,19 +361,19 @@ namespace ASC.Core.Common.Configuration var additional = fromConfig.AdditionalKeys.ToDictionary(prop => prop, prop => fromConfig[prop]); additional.Add(HandlerTypeKey, HandlerType.AssemblyQualifiedName); - return new DataStoreConsumer(fromConfig.TenantManager, fromConfig.CoreBaseSettings, fromConfig.CoreSettings, fromConfig.ConsumerFactory, fromConfig.Configuration, fromConfig.Cache, fromConfig.Name, fromConfig.Order, props, additional); + return new DataStoreConsumer(fromConfig.TenantManager, fromConfig.CoreBaseSettings, fromConfig.CoreSettings, fromConfig.Configuration, fromConfig.Cache, fromConfig.Name, fromConfig.Order, props, additional); } public object Clone() { - return new DataStoreConsumer(TenantManager, CoreBaseSettings, CoreSettings, ConsumerFactory, Configuration, Cache, Name, Order, Props.ToDictionary(r => r.Key, r => r.Value), Additional.ToDictionary(r => r.Key, r => r.Value)); + return new DataStoreConsumer(TenantManager, CoreBaseSettings, CoreSettings, Configuration, Cache, Name, Order, Props.ToDictionary(r => r.Key, r => r.Value), Additional.ToDictionary(r => r.Key, r => r.Value)); } } public class ConsumerFactory { public ILifetimeScope Builder { get; set; } - + public ConsumerFactory(IContainer builder) { Builder = builder; diff --git a/common/ASC.FederatedLogin/LoginProviders/BaseLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/BaseLoginProvider.cs index b520a51af8..220325bb42 100644 --- a/common/ASC.FederatedLogin/LoginProviders/BaseLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/BaseLoginProvider.cs @@ -80,13 +80,12 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { Signature = signature; InstanceCrypto = instanceCrypto; diff --git a/common/ASC.FederatedLogin/LoginProviders/BitlyLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/BitlyLoginProvider.cs index c417c76f3d..43a16d9306 100644 --- a/common/ASC.FederatedLogin/LoginProviders/BitlyLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/BitlyLoginProvider.cs @@ -45,22 +45,17 @@ namespace ASC.FederatedLogin.LoginProviders { private string BitlyClientId { - get { return Instance["bitlyClientId"]; } + get { return this["bitlyClientId"]; } } private string BitlyClientSecret { - get { return Instance["bitlyClientSecret"]; } + get { return this["bitlyClientSecret"]; } } private string BitlyUrl { - get { return Instance["bitlyUrl"]; } - } - - private BitlyLoginProvider Instance - { - get { return ConsumerFactory.Get(); } + get { return this["bitlyUrl"]; } } public BitlyLoginProvider() { } @@ -69,11 +64,10 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/BoxLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/BoxLoginProvider.cs index e76dd38c16..902f44253c 100644 --- a/common/ASC.FederatedLogin/LoginProviders/BoxLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/BoxLoginProvider.cs @@ -37,14 +37,6 @@ namespace ASC.FederatedLogin.LoginProviders { public class BoxLoginProvider : Consumer, IOAuthProvider { - public BoxLoginProvider Instance - { - get - { - return ConsumerFactory.Get(); - } - } - public string Scopes { get { return ""; } } public string CodeUrl { get { return "https://app.box.com/api/oauth2/authorize"; } } public string AccessTokenUrl { get { return "https://app.box.com/api/oauth2/token"; } } @@ -68,11 +60,10 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } } diff --git a/common/ASC.FederatedLogin/LoginProviders/DocuSignLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/DocuSignLoginProvider.cs index 0f618198fe..1a8f0a8c02 100644 --- a/common/ASC.FederatedLogin/LoginProviders/DocuSignLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/DocuSignLoginProvider.cs @@ -40,11 +40,6 @@ namespace ASC.FederatedLogin.LoginProviders { public class DocuSignLoginProvider : Consumer, IOAuthProvider { - public DocuSignLoginProvider Instance - { - get { return ConsumerFactory.Get(); } - } - public string Scopes { get { return "signature"; } } public string CodeUrl { get { return DocuSignHost + "/oauth/auth"; } } public string AccessTokenUrl { get { return DocuSignHost + "/oauth/token"; } } @@ -69,11 +64,10 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/DropboxLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/DropboxLoginProvider.cs index 70b7bf689d..7c3281a853 100644 --- a/common/ASC.FederatedLogin/LoginProviders/DropboxLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/DropboxLoginProvider.cs @@ -37,11 +37,6 @@ namespace ASC.FederatedLogin.LoginProviders { public class DropboxLoginProvider : Consumer, IOAuthProvider { - public DropboxLoginProvider Instance - { - get { return ConsumerFactory.Get(); } - } - public string Scopes { get { return ""; } } public string CodeUrl { get { return "https://www.dropbox.com/oauth2/authorize"; } } public string AccessTokenUrl { get { return "https://api.dropboxapi.com/oauth2/token"; } } @@ -65,11 +60,10 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } } @@ -77,7 +71,7 @@ namespace ASC.FederatedLogin.LoginProviders { public static DIHelper AddDropboxLoginProviderService(this DIHelper services) { - services.TryAddScoped(); + //services.TryAddScoped(); return services .AddConsumerFactoryService() .AddKafkaService() diff --git a/common/ASC.FederatedLogin/LoginProviders/FacebookLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/FacebookLoginProvider.cs index 28d4cea7e9..4db38ab881 100644 --- a/common/ASC.FederatedLogin/LoginProviders/FacebookLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/FacebookLoginProvider.cs @@ -57,13 +57,12 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } public override LoginProfile GetLoginProfile(string accessToken) { diff --git a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs index 0f8b075503..91a842ed3e 100644 --- a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs @@ -72,13 +72,12 @@ namespace ASC.FederatedLogin.LoginProviders public GoogleLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } public override LoginProfile GetLoginProfile(string accessToken) { diff --git a/common/ASC.FederatedLogin/LoginProviders/GosUslugiLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/GosUslugiLoginProvider.cs index 41655ce10f..134667d31e 100644 --- a/common/ASC.FederatedLogin/LoginProviders/GosUslugiLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/GosUslugiLoginProvider.cs @@ -101,13 +101,12 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/LinkedInLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/LinkedInLoginProvider.cs index b117573e85..89b495ca54 100644 --- a/common/ASC.FederatedLogin/LoginProviders/LinkedInLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/LinkedInLoginProvider.cs @@ -80,13 +80,12 @@ namespace ASC.FederatedLogin.LoginProviders public LinkedInLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } public override LoginProfile GetLoginProfile(string accessToken) { diff --git a/common/ASC.FederatedLogin/LoginProviders/MailRuLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/MailRuLoginProvider.cs index 963e620202..c589e7396a 100644 --- a/common/ASC.FederatedLogin/LoginProviders/MailRuLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/MailRuLoginProvider.cs @@ -83,13 +83,12 @@ namespace ASC.FederatedLogin.LoginProviders public MailRuLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/OneDriveLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/OneDriveLoginProvider.cs index 5a765a09a4..c578781740 100644 --- a/common/ASC.FederatedLogin/LoginProviders/OneDriveLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/OneDriveLoginProvider.cs @@ -40,11 +40,6 @@ namespace ASC.FederatedLogin.LoginProviders private const string OneDriveOauthUrl = "https://login.live.com/"; public const string OneDriveApiUrl = "https://api.onedrive.com"; - public OneDriveLoginProvider Instance - { - get { return ConsumerFactory.Get(); } - } - public string Scopes { get { return "wl.signin wl.skydrive_update wl.offline_access"; } } public string CodeUrl { get { return OneDriveOauthUrl + "oauth20_authorize.srf"; } } public string AccessTokenUrl { get { return OneDriveOauthUrl + "oauth20_token.srf"; } } @@ -68,11 +63,10 @@ namespace ASC.FederatedLogin.LoginProviders TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } } diff --git a/common/ASC.FederatedLogin/LoginProviders/VKLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/VKLoginProvider.cs index 7426005b60..46e1f24128 100644 --- a/common/ASC.FederatedLogin/LoginProviders/VKLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/VKLoginProvider.cs @@ -87,13 +87,12 @@ namespace ASC.FederatedLogin.LoginProviders public VKLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/WordpressLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/WordpressLoginProvider.cs index 9cd0ce34c6..532c7a160f 100644 --- a/common/ASC.FederatedLogin/LoginProviders/WordpressLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/WordpressLoginProvider.cs @@ -52,13 +52,12 @@ namespace ASC.FederatedLogin.LoginProviders public WordpressLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } diff --git a/common/ASC.FederatedLogin/LoginProviders/YahooLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/YahooLoginProvider.cs index b6013ebd95..3b392180ae 100644 --- a/common/ASC.FederatedLogin/LoginProviders/YahooLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/YahooLoginProvider.cs @@ -55,13 +55,12 @@ namespace ASC.FederatedLogin.LoginProviders public YahooLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } public OAuth20Token Auth(HttpContext context) { diff --git a/common/ASC.FederatedLogin/LoginProviders/YandexLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/YandexLoginProvider.cs index 38661ff692..adc8a61f98 100644 --- a/common/ASC.FederatedLogin/LoginProviders/YandexLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/YandexLoginProvider.cs @@ -80,13 +80,12 @@ namespace ASC.FederatedLogin.LoginProviders public YandexLoginProvider(TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, Signature signature, InstanceCrypto instanceCrypto, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, signature, instanceCrypto, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, signature, instanceCrypto, name, order, props, additional) { } diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index ce9caf50cb..fb93e9b7c0 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -18,9 +18,18 @@ none true + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -34,6 +43,10 @@ + + + + True diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 79d7dd7cf6..b4a6eba053 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -138,10 +138,6 @@ namespace ASC.Api.Documents WebItemSecurity webItemSecurity, CoreBaseSettings coreBaseSettings, ThirdpartyConfiguration thirdpartyConfiguration, - BoxLoginProvider boxLoginProvider, - DropboxLoginProvider dropboxLoginProvider, - GoogleLoginProvider googleLoginProvider, - OneDriveLoginProvider oneDriveLoginProvider, MessageService messageService, CommonLinkUtility commonLinkUtility, DocumentServiceConnector documentServiceConnector, @@ -173,17 +169,17 @@ namespace ASC.Api.Documents WebItemSecurity = webItemSecurity; CoreBaseSettings = coreBaseSettings; ThirdpartyConfiguration = thirdpartyConfiguration; - BoxLoginProvider = boxLoginProvider; - DropboxLoginProvider = dropboxLoginProvider; - GoogleLoginProvider = googleLoginProvider; - OneDriveLoginProvider = oneDriveLoginProvider; + ConsumerFactory = consumerFactory; + BoxLoginProvider = ConsumerFactory.Get(); + DropboxLoginProvider = ConsumerFactory.Get(); + GoogleLoginProvider = ConsumerFactory.Get(); + OneDriveLoginProvider = ConsumerFactory.Get(); MessageService = messageService; CommonLinkUtility = commonLinkUtility; DocumentServiceConnector = documentServiceConnector; FolderContentWrapperHelper = folderContentWrapperHelper; WordpressToken = wordpressToken; WordpressHelper = wordpressHelper; - ConsumerFactory = consumerFactory; EasyBibHelper = easyBibHelper; ChunkedUploadSessionHelper = chunkedUploadSessionHelper; ProductEntryPoint = productEntryPoint; @@ -205,9 +201,9 @@ namespace ASC.Api.Documents /// Folders /// My folder contents [Read("@my")] - public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.GetFolderMy(), userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.FolderMy, userIdOrGroupId, filterType); } /// @@ -1329,19 +1325,19 @@ namespace ASC.Api.Documents if (ThirdpartyConfiguration.SupportBoxInclusion) { - result.Add(new List { "Box", BoxLoginProvider.Instance.ClientID, BoxLoginProvider.Instance.RedirectUri }); + result.Add(new List { "Box", BoxLoginProvider.ClientID, BoxLoginProvider.RedirectUri }); } if (ThirdpartyConfiguration.SupportDropboxInclusion) { - result.Add(new List { "DropboxV2", DropboxLoginProvider.Instance.ClientID, DropboxLoginProvider.Instance.RedirectUri }); + result.Add(new List { "DropboxV2", DropboxLoginProvider.ClientID, DropboxLoginProvider.RedirectUri }); } if (ThirdpartyConfiguration.SupportGoogleDriveInclusion) { - result.Add(new List { "GoogleDrive", GoogleLoginProvider.Instance.ClientID, GoogleLoginProvider.Instance.RedirectUri }); + result.Add(new List { "GoogleDrive", GoogleLoginProvider.ClientID, GoogleLoginProvider.RedirectUri }); } if (ThirdpartyConfiguration.SupportOneDriveInclusion) { - result.Add(new List { "OneDrive", OneDriveLoginProvider.Instance.ClientID, OneDriveLoginProvider.Instance.RedirectUri }); + result.Add(new List { "OneDrive", OneDriveLoginProvider.ClientID, OneDriveLoginProvider.RedirectUri }); } if (ThirdpartyConfiguration.SupportSharePointInclusion) { diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index 4930874b7a..4f583d53dc 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -28,6 +28,7 @@ using System; using ASC.Common; using ASC.Files.Core.Security; +using ASC.Files.Thirdparty; using Microsoft.Extensions.DependencyInjection; @@ -38,9 +39,10 @@ namespace ASC.Files.Core.Data public IServiceProvider ServiceProvider { get; } public IProviderDao ProviderDao { get; } - public DaoFactory(IServiceProvider serviceProvider) + public DaoFactory(IServiceProvider serviceProvider, IProviderDao providerDao) { ServiceProvider = serviceProvider; + ProviderDao = providerDao; } public IFileDao GetFileDao() @@ -73,6 +75,7 @@ namespace ASC.Files.Core.Data .AddFolderDaoService() .AddTagDaoService() .AddSecurityDaoService() + .AddCachedProviderAccountDaoService() ; } } diff --git a/products/ASC.Files/Server/Core/EF/DbFilesThirdpartyAccount.cs b/products/ASC.Files/Server/Core/EF/DbFilesThirdpartyAccount.cs index 301cabaf5c..061588256d 100644 --- a/products/ASC.Files/Server/Core/EF/DbFilesThirdpartyAccount.cs +++ b/products/ASC.Files/Server/Core/EF/DbFilesThirdpartyAccount.cs @@ -1,17 +1,19 @@ using System; using System.ComponentModel.DataAnnotations.Schema; +using ASC.Core.Common.EF; + namespace ASC.Files.Core.EF { [Table("files_thirdparty_account")] - public class DbFilesThirdpartyAccount : IDbFile + public class DbFilesThirdpartyAccount : BaseEntity, IDbFile, IDbSearch { public int Id { get; set; } public string Provider { get; set; } [Column("customer_title")] - public string CustomerTitle { get; set; } + public string Title { get; set; } [Column("user_name")] public string UserName { get; set; } @@ -33,5 +35,7 @@ namespace ASC.Files.Core.EF [Column("tenant_id")] public int TenantId { get; set; } - } + + public override object[] GetKeys() => new object[] { Id }; + }; } diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 072cd315dd..a4aafb349c 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -41,6 +41,7 @@ using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common; +using ASC.Core.Common.Configuration; using ASC.Core.Users; using ASC.Data.Storage; using ASC.ElasticSearch; @@ -112,6 +113,7 @@ namespace ASC.Web.Files.Services.WCFService public IServiceProvider ServiceProvider { get; } public FileSharingAceHelper FileSharingAceHelper { get; } public ApiContext ApiContext { get; } + public ConsumerFactory ConsumerFactory { get; } public ILog Logger { get; set; } public FileStorageService( @@ -131,7 +133,6 @@ namespace ASC.Web.Files.Services.WCFService DisplayUserSettingsHelper displayUserSettingsHelper, IHttpContextAccessor httpContextAccessor, IOptionsMonitor optionMonitor, - DocuSignLoginProvider docuSignLoginProvider, PathProvider pathProvider, FileSecurity fileSecurity, SocketManager socketManager, @@ -153,7 +154,8 @@ namespace ASC.Web.Files.Services.WCFService UrlShortener urlShortener, IServiceProvider serviceProvider, FileSharingAceHelper fileSharingAceHelper, - ApiContext apiContext) + ApiContext apiContext, + ConsumerFactory consumerFactory) { Global = global; GlobalStore = globalStore; @@ -170,7 +172,6 @@ namespace ASC.Web.Files.Services.WCFService CustomNamingPeople = customNamingPeople; DisplayUserSettingsHelper = displayUserSettingsHelper; HttpContextAccessor = httpContextAccessor; - DocuSignLoginProvider = docuSignLoginProvider; PathProvider = pathProvider; FileSecurity = fileSecurity; SocketManager = socketManager; @@ -193,6 +194,7 @@ namespace ASC.Web.Files.Services.WCFService ServiceProvider = serviceProvider; FileSharingAceHelper = fileSharingAceHelper; ApiContext = apiContext; + ConsumerFactory = consumerFactory; Logger = optionMonitor.Get("ASC.Files"); } @@ -854,7 +856,7 @@ namespace ASC.Web.Files.Services.WCFService { if (tagLocked == null) { - tagLocked = new Tag("locked", TagType.Locked, AuthContext.CurrentAccount.ID, 0).AddEntry(file); + tagLocked = new Tag("locked", TagType.Locked, AuthContext.CurrentAccount.ID, 0).AddEntry(file); tagDao.SaveTags(tagLocked); } @@ -1221,7 +1223,7 @@ namespace ASC.Web.Files.Services.WCFService || !Global.IsAdministrator && !FilesSettingsHelper.EnableThirdParty || !ThirdpartyConfiguration.SupportDocuSignInclusion, FilesCommonResource.ErrorMassage_SecurityException_Create); - var token = DocuSignLoginProvider.Instance.GetAccessToken(code); + var token = ConsumerFactory.Get().GetAccessToken(code); DocuSignHelper.ValidateToken(token); DocuSignToken.SaveToken(token); return true; diff --git a/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs new file mode 100644 index 0000000000..e726e7afa8 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs @@ -0,0 +1,136 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Concurrent; +using System.Globalization; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.Configuration; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Security.Cryptography; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty +{ + internal class CachedProviderAccountDaoNotify + { + public ConcurrentDictionary Cache { get; private set; } + public ICacheNotify CacheNotify { get; private set; } + + public CachedProviderAccountDaoNotify(ICacheNotify cacheNotify) + { + Cache = new ConcurrentDictionary(); + CacheNotify = cacheNotify; + cacheNotify.Subscribe((i) => RemoveFromCache(i.Key), CacheNotifyAction.Any); + } + private void RemoveFromCache(string key) + { + Cache.TryRemove(key, out _); + } + } + + internal class CachedProviderAccountDao : ProviderAccountDao + { + private readonly ConcurrentDictionary cache; + private readonly ICacheNotify cacheNotify; + + private readonly string _rootKey; + + public CachedProviderAccountDao( + IServiceProvider serviceProvider, + TenantUtil tenantUtil, + TenantManager tenantManager, + InstanceCrypto instanceCrypto, + SecurityContext securityContext, + ConsumerFactory consumerFactory, + DbContextManager dbContextManager, + IOptionsMonitor options, + CachedProviderAccountDaoNotify cachedProviderAccountDaoNotify) + : base(serviceProvider, tenantUtil, tenantManager, instanceCrypto, securityContext, consumerFactory, dbContextManager, options) + { + cache = cachedProviderAccountDaoNotify.Cache; + cacheNotify = cachedProviderAccountDaoNotify.CacheNotify; + _rootKey = tenantManager.GetCurrentTenant().TenantId.ToString(CultureInfo.InvariantCulture); + } + + public override IProviderInfo GetProviderInfo(int linkId) + { + var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); + if (!cache.TryGetValue(key, out var value)) + { + value = base.GetProviderInfo(linkId); + cache.TryAdd(key, value); + } + return value; + } + + public override void RemoveProviderInfo(int linkId) + { + base.RemoveProviderInfo(linkId); + + var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); + cacheNotify.Publish(new ProviderAccountCacheItem { Key = key }, CacheNotifyAction.Any); + } + + public override int UpdateProviderInfo(int linkId, string customerTitle, AuthData authData, FolderType folderType, Guid? userId = null) + { + var result = base.UpdateProviderInfo(linkId, customerTitle, authData, folderType, userId); + + var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); + cacheNotify.Publish(new ProviderAccountCacheItem { Key = key }, CacheNotifyAction.Any); + return result; + } + + public override int UpdateProviderInfo(int linkId, AuthData authData) + { + var result = base.UpdateProviderInfo(linkId, authData); + + var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); + cacheNotify.Publish(new ProviderAccountCacheItem { Key = key }, CacheNotifyAction.Any); + return result; + } + } + public static class CachedProviderAccountDaoExtention + { + public static DIHelper AddCachedProviderAccountDaoService(this DIHelper services) + { + services.TryAddScoped(); + + services.TryAddSingleton(); + + return services + .AddProviderAccountDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs new file mode 100644 index 0000000000..79180247ed --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -0,0 +1,435 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Security.Cryptography; +using ASC.Web.Files.Classes; +using ASC.Web.Studio.Core; + +using Dropbox.Api.Files; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal abstract class DropboxDaoBase + { + protected readonly DropboxDaoSelector DropboxDaoSelector; + + public int TenantID { get; private set; } + public DropboxProviderInfo DropboxProviderInfo { get; private set; } + public string PathPrefix { get; private set; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantUtil TenantUtil { get; } + public SetupInfo SetupInfo { get; } + public FilesDbContext FilesDbContext { get; } + + public DropboxDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + { + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + SetupInfo = setupInfo; + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + } + + protected DropboxDaoBase(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + { + DropboxProviderInfo = dropboxInfo.DropboxProviderInfo; + PathPrefix = dropboxInfo.PathPrefix; + DropboxDaoSelector = dropboxDaoSelector; + } + + public void Dispose() + { + DropboxProviderInfo.Dispose(); + } + + protected string MappingID(string id, bool saveIfNotExist = false) + { + if (id == null) return null; + + string result; + if (id.ToString().StartsWith("dropbox")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + return result; + } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + private static string GetTenantColumnName(string table) + { + const string tenant = "tenant_id"; + if (!table.Contains(" ")) return tenant; + return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant; + } + + + protected static string GetParentFolderPath(Metadata dropboxItem) + { + if (dropboxItem == null || IsRoot(dropboxItem.AsFolder)) + return null; + + var pathLength = dropboxItem.PathDisplay.Length - dropboxItem.Name.Length; + return dropboxItem.PathDisplay.Substring(0, pathLength > 1 ? pathLength - 1 : 0); + } + + protected static string MakeDropboxPath(object entryId) + { + return Convert.ToString(entryId, CultureInfo.InvariantCulture); + } + + protected string MakeDropboxPath(Metadata dropboxItem) + { + string path = null; + if (dropboxItem != null) + { + path = dropboxItem.PathDisplay; + } + + return path; + } + + protected string MakeId(Metadata dropboxItem) + { + return MakeId(MakeDropboxPath(dropboxItem)); + } + + protected string MakeId(string path = null) + { + return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "/" ? "" : ("-" + path.Replace('/', '|'))); + } + + protected string MakeFolderTitle(FolderMetadata dropboxFolder) + { + if (dropboxFolder == null || IsRoot(dropboxFolder)) + { + return DropboxProviderInfo.CustomerTitle; + } + + return Global.ReplaceInvalidCharsAndTruncate(dropboxFolder.Name); + } + + protected string MakeFileTitle(FileMetadata dropboxFile) + { + if (dropboxFile == null || string.IsNullOrEmpty(dropboxFile.Name)) + { + return DropboxProviderInfo.ProviderKey; + } + + return Global.ReplaceInvalidCharsAndTruncate(dropboxFile.Name); + } + + protected Folder ToFolder(FolderMetadata dropboxFolder) + { + if (dropboxFolder == null) return null; + if (dropboxFolder is ErrorFolder) + { + //Return error entry + return ToErrorFolder(dropboxFolder as ErrorFolder); + } + + var isRoot = IsRoot(dropboxFolder); + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(dropboxFolder); + folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderPath(dropboxFolder)); + folder.CreateBy = DropboxProviderInfo.Owner; + folder.CreateOn = isRoot ? DropboxProviderInfo.CreateOn : default; + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = DropboxProviderInfo.Owner; + folder.ModifiedOn = isRoot ? DropboxProviderInfo.CreateOn : default; + folder.ProviderId = DropboxProviderInfo.ID; + folder.ProviderKey = DropboxProviderInfo.ProviderKey; + folder.RootFolderCreator = DropboxProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = DropboxProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeFolderTitle(dropboxFolder); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + + if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) + folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); + + if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc) + folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn); + + return folder; + } + + protected static bool IsRoot(FolderMetadata dropboxFolder) + { + return dropboxFolder != null && dropboxFolder.Id == "/"; + } + + private File ToErrorFile(ErrorFile dropboxFile) + { + if (dropboxFile == null) return null; + var file = ServiceProvider.GetService>(); + file.ID = MakeId(dropboxFile.ErrorId); + file.CreateBy = DropboxProviderInfo.Owner; + file.CreateOn = TenantUtil.DateTimeNow(); + file.ModifiedBy = DropboxProviderInfo.Owner; + file.ModifiedOn = TenantUtil.DateTimeNow(); + file.ProviderId = DropboxProviderInfo.ID; + file.ProviderKey = DropboxProviderInfo.ProviderKey; + file.RootFolderCreator = DropboxProviderInfo.Owner; + file.RootFolderId = MakeId(); + file.RootFolderType = DropboxProviderInfo.RootFolderType; + file.Title = MakeFileTitle(dropboxFile); + file.Error = dropboxFile.Error; + + return file; + } + + private Folder ToErrorFolder(ErrorFolder dropboxFolder) + { + if (dropboxFolder == null) return null; + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(dropboxFolder.ErrorId); + folder.ParentFolderID = null; + folder.CreateBy = DropboxProviderInfo.Owner; + folder.CreateOn = TenantUtil.DateTimeNow(); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = DropboxProviderInfo.Owner; + folder.ModifiedOn = TenantUtil.DateTimeNow(); + folder.ProviderId = DropboxProviderInfo.ID; + folder.ProviderKey = DropboxProviderInfo.ProviderKey; + folder.RootFolderCreator = DropboxProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = DropboxProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeFolderTitle(dropboxFolder); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + folder.Error = dropboxFolder.Error; + + return folder; + } + + public File ToFile(FileMetadata dropboxFile) + { + if (dropboxFile == null) return null; + + if (dropboxFile is ErrorFile) + { + //Return error entry + return ToErrorFile(dropboxFile as ErrorFile); + } + + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(dropboxFile); + file.Access = FileShare.None; + file.ContentLength = (long)dropboxFile.Size; + file.CreateBy = DropboxProviderInfo.Owner; + file.CreateOn = TenantUtil.DateTimeFromUtc(dropboxFile.ServerModified); + file.FileStatus = FileStatus.None; + file.FolderID = MakeId(GetParentFolderPath(dropboxFile)); + file.ModifiedBy = DropboxProviderInfo.Owner; + file.ModifiedOn = TenantUtil.DateTimeFromUtc(dropboxFile.ServerModified); + file.NativeAccessor = dropboxFile; + file.ProviderId = DropboxProviderInfo.ID; + file.ProviderKey = DropboxProviderInfo.ProviderKey; + file.Title = MakeFileTitle(dropboxFile); + file.RootFolderId = MakeId(); + file.RootFolderType = DropboxProviderInfo.RootFolderType; + file.RootFolderCreator = DropboxProviderInfo.Owner; + file.Shared = false; + file.Version = 1; + + return file; + } + + public Folder GetRootFolder(string folderId) + { + return ToFolder(GetDropboxFolder(string.Empty)); + } + + protected FolderMetadata GetDropboxFolder(string folderId) + { + var dropboxFolderPath = MakeDropboxPath(folderId); + try + { + var folder = DropboxProviderInfo.GetDropboxFolder(dropboxFolderPath); + return folder; + } + catch (Exception ex) + { + return new ErrorFolder(ex, dropboxFolderPath); + } + } + + protected FileMetadata GetDropboxFile(object fileId) + { + var dropboxFilePath = MakeDropboxPath(fileId); + try + { + var file = DropboxProviderInfo.GetDropboxFile(dropboxFilePath); + return file; + } + catch (Exception ex) + { + return new ErrorFile(ex, dropboxFilePath); + } + } + + protected IEnumerable GetChildren(object folderId) + { + return GetDropboxItems(folderId).Select(MakeId); + } + + protected List GetDropboxItems(object parentId, bool? folder = null) + { + var dropboxFolderPath = MakeDropboxPath(parentId); + var items = DropboxProviderInfo.GetDropboxItems(dropboxFolderPath); + + if (folder.HasValue) + { + if (folder.Value) + { + return items.Where(i => i.AsFolder != null).ToList(); + } + + return items.Where(i => i.AsFile != null).ToList(); + } + + return items; + } + + protected sealed class ErrorFolder : FolderMetadata + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorFolder(Exception e, object id) + { + ErrorId = id.ToString(); + if (e != null) + { + Error = e.Message; + } + } + } + + protected sealed class ErrorFile : FileMetadata + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorFile(Exception e, object id) + { + ErrorId = id.ToString(); + if (e != null) + { + Error = e.Message; + } + } + } + + protected string GetAvailableTitle(string requestTitle, string parentFolderPath, Func isExist) + { + if (!isExist(requestTitle, parentFolderPath)) return requestTitle; + + var re = new Regex(@"( \(((?[0-9])+)\)(\.[^\.]*)?)$"); + var match = re.Match(requestTitle); + + if (!match.Success) + { + var insertIndex = requestTitle.Length; + if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1) + { + insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture); + } + requestTitle = requestTitle.Insert(insertIndex, " (1)"); + } + + while (isExist(requestTitle, parentFolderPath)) + { + requestTitle = re.Replace(requestTitle, MatchEvaluator); + } + return requestTitle; + } + + private static string MatchEvaluator(Match match) + { + var index = Convert.ToInt32(match.Groups[2].Value); + var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); + return string.Format(" ({0}){1}", index + 1, staticText); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs new file mode 100644 index 0000000000..94f637065f --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs @@ -0,0 +1,149 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Globalization; +using System.Text.RegularExpressions; + +using ASC.Core; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxDaoSelector : RegexDaoSelectorBase + { + public TenantManager TenantManager { get; } + public IDaoFactory DaoFactory { get; } + + internal class DropboxInfo + { + public DropboxProviderInfo DropboxProviderInfo { get; set; } + + public string Path { get; set; } + public string PathPrefix { get; set; } + } + + public DropboxDaoSelector(TenantManager tenantManager, IDaoFactory daoFactory) + : base(new Regex(@"^dropbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + TenantManager = tenantManager; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + return new DropboxFileDao(GetInfo(id), this); + } + + public override IFolderDao GetFolderDao(string id) + { + return new DropboxFolderDao(GetInfo(id), this); + } + + public override ITagDao GetTagDao(string id) + { + return new DropboxTagDao(GetInfo(id), this); + } + + public override ISecurityDao GetSecurityDao(string id) + { + return new DropboxSecurityDao(GetInfo(id), this); + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(Convert.ToString(id, CultureInfo.InvariantCulture)); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a Dropbox id"); + } + return base.ConvertId(null); + } + + private DropboxInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = Convert.ToString(objectId, CultureInfo.InvariantCulture); + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new DropboxInfo + { + Path = match.Groups["path"].Value, + DropboxProviderInfo = providerInfo, + PathPrefix = "dropbox-" + match.Groups["id"].Value + }; + } + throw new ArgumentException("Id is not a Dropbox id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(Convert.ToString(id, CultureInfo.InvariantCulture)); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private DropboxProviderInfo GetProviderInfo(int linkId) + { + DropboxProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + try + { + info = (DropboxProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(DropboxProviderInfo dropboxProviderInfo, string newTitle) + { + //TODO + //using (var dbDao = new CachedProviderAccountDao(TenantManager.GetCurrentTenant().TenantId, FileConstant.DatabaseId)) + //{ + // dbDao.UpdateProviderInfo(dropboxProviderInfo.ID, newTitle, null, dropboxProviderInfo.RootFolderType); + // dropboxProviderInfo.UpdateTitle(newTitle); //This will update cached version too + //} + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs new file mode 100644 index 0000000000..d409f2d51a --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -0,0 +1,596 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +using Dropbox.Api.Files; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxFileDao : DropboxDaoBase, IFileDao + { + public DropboxFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public DropboxFileDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + : base(dropboxInfo, dropboxDaoSelector) + { + } + + public void InvalidateCache(string fileId) + { + var dropboxFilePath = MakeDropboxPath(fileId); + DropboxProviderInfo.CacheReset(dropboxFilePath, true); + + var dropboxFile = GetDropboxFile(fileId); + var parentPath = GetParentFolderPath(dropboxFile); + if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ToFile(GetDropboxFile(fileId)); + } + + public File GetFile(string parentId, string title) + { + var metadata = GetDropboxItems(parentId, false) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + return metadata == null + ? null + : ToFile(metadata.AsFile); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ToFile(GetDropboxFile(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + if (fileIds == null || fileIds.Length == 0) return new List>(); + return fileIds.Select(GetDropboxFile).Select(ToFile).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + return GetDropboxItems(parentId, false).Select(entry => MakeId(entry)).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = GetDropboxItems(parentId, false).Select(item => ToFile(item.AsFile)); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public Stream GetFileStream(File file, long offset) + { + var dropboxFilePath = MakeDropboxPath(file.ID); + DropboxProviderInfo.CacheReset(dropboxFilePath, true); + + var dropboxFile = GetDropboxFile(file.ID); + if (dropboxFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + if (dropboxFile is ErrorFile) throw new Exception(((ErrorFile)dropboxFile).Error); + + var fileStream = DropboxProviderInfo.Storage.DownloadStream(MakeDropboxPath(dropboxFile), (int)offset); + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public File SaveFile(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + if (fileStream == null) throw new ArgumentNullException("fileStream"); + + FileMetadata newDropboxFile = null; + + if (file.ID != null) + { + var filePath = MakeDropboxPath(file.ID); + newDropboxFile = DropboxProviderInfo.Storage.SaveStream(filePath, fileStream); + if (!newDropboxFile.Name.Equals(file.Title)) + { + var parentFolderPath = GetParentFolderPath(newDropboxFile); + file.Title = GetAvailableTitle(file.Title, parentFolderPath, IsExist); + newDropboxFile = DropboxProviderInfo.Storage.MoveFile(filePath, parentFolderPath, file.Title); + } + } + else if (file.FolderID != null) + { + var folderPath = MakeDropboxPath(file.FolderID); + file.Title = GetAvailableTitle(file.Title, folderPath, IsExist); + newDropboxFile = DropboxProviderInfo.Storage.CreateFile(fileStream, file.Title, folderPath); + } + + DropboxProviderInfo.CacheReset(newDropboxFile); + var parentPath = GetParentFolderPath(newDropboxFile); + if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + + return ToFile(newDropboxFile); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var dropboxFile = GetDropboxFile(fileId); + if (dropboxFile == null) return; + var id = MakeId(dropboxFile); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(dropboxFile is ErrorFile)) + { + DropboxProviderInfo.Storage.DeleteItem(dropboxFile); + } + + DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); + var parentFolderPath = GetParentFolderPath(dropboxFile); + if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + } + + public bool IsExist(string title, object folderId) + { + return GetDropboxItems(folderId, false) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public string MoveFile(string fileId, string toFolderId) + { + var dropboxFile = GetDropboxFile(fileId); + if (dropboxFile is ErrorFile) throw new Exception(((ErrorFile)dropboxFile).Error); + + var toDropboxFolder = GetDropboxFolder(toFolderId); + if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); + + var fromFolderPath = GetParentFolderPath(dropboxFile); + + dropboxFile = DropboxProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); + + DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); + DropboxProviderInfo.CacheReset(fromFolderPath); + DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + + return MakeId(dropboxFile); + } + + public File CopyFile(string fileId, string toFolderId) + { + var dropboxFile = GetDropboxFile(fileId); + if (dropboxFile is ErrorFile) throw new Exception(((ErrorFile)dropboxFile).Error); + + var toDropboxFolder = GetDropboxFolder(toFolderId); + if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); + + var newDropboxFile = DropboxProviderInfo.Storage.CopyFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); + + DropboxProviderInfo.CacheReset(newDropboxFile); + DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + + return ToFile(newDropboxFile); + } + + public string FileRename(File file, string newTitle) + { + var dropboxFile = GetDropboxFile(file.ID); + var parentFolderPath = GetParentFolderPath(dropboxFile); + newTitle = GetAvailableTitle(newTitle, parentFolderPath, IsExist); + + dropboxFile = DropboxProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), parentFolderPath, newTitle); + + DropboxProviderInfo.CacheReset(dropboxFile); + var parentPath = GetParentFolderPath(dropboxFile); + if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + + return MakeId(dropboxFile); + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + #region chunking + + private File RestoreIds(File file) + { + if (file == null) return null; + + if (file.ID != null) + file.ID = MakeId(file.ID.ToString()); + + if (file.FolderID != null) + file.FolderID = MakeId(file.FolderID.ToString()); + + return file; + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + if (SetupInfo.ChunkUploadSize > contentLength) + return new ChunkedUploadSession(RestoreIds(file), contentLength) { UseChunks = false }; + + var uploadSession = new ChunkedUploadSession(file, contentLength); + + var dropboxSession = DropboxProviderInfo.Storage.CreateResumableSession(); + if (dropboxSession != null) + { + uploadSession.Items["DropboxSession"] = dropboxSession; + } + else + { + uploadSession.Items["TempPath"] = Path.GetTempFileName(); + } + + uploadSession.File = RestoreIds(uploadSession.File); + return uploadSession; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, stream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + if (uploadSession.Items.ContainsKey("DropboxSession")) + { + var dropboxSession = uploadSession.GetItemOrDefault("DropboxSession"); + DropboxProviderInfo.Storage.Transfer(dropboxSession, uploadSession.BytesUploaded, stream); + } + else + { + var tempPath = uploadSession.GetItemOrDefault("TempPath"); + using (var fs = new FileStream(tempPath, FileMode.Append)) + { + stream.CopyTo(fs); + } + } + + uploadSession.BytesUploaded += chunkLength; + + if (uploadSession.BytesUploaded == uploadSession.BytesTotal) + { + uploadSession.File = FinalizeUploadSession(uploadSession); + } + else + { + uploadSession.File = RestoreIds(uploadSession.File); + } + } + + public File FinalizeUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("DropboxSession")) + { + var dropboxSession = uploadSession.GetItemOrDefault("DropboxSession"); + + Metadata dropboxFile; + var file = uploadSession.File; + if (file.ID != null) + { + var dropboxFilePath = MakeDropboxPath(file.ID); + dropboxFile = DropboxProviderInfo.Storage.FinishResumableSession(dropboxSession, dropboxFilePath, uploadSession.BytesUploaded); + } + else + { + var folderPath = MakeDropboxPath(file.FolderID); + var title = GetAvailableTitle(file.Title, folderPath, IsExist); + dropboxFile = DropboxProviderInfo.Storage.FinishResumableSession(dropboxSession, folderPath, title, uploadSession.BytesUploaded); + } + + DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile)); + DropboxProviderInfo.CacheReset(GetParentFolderPath(dropboxFile), false); + + return ToFile(dropboxFile.AsFile); + } + + using (var fs = new FileStream(uploadSession.GetItemOrDefault("TempPath"), + FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + return SaveFile(uploadSession.File, fs); + } + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("TempPath")) + { + System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + } + } + + #endregion + + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs new file mode 100644 index 0000000000..84a248ed68 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -0,0 +1,415 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxFolderDao : DropboxDaoBase, IFolderDao + { + public DropboxFolderDao(IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public DropboxFolderDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + : base(dropboxInfo, dropboxDaoSelector) + { + } + + public Folder GetFolder(string folderId) + { + return ToFolder(GetDropboxFolder(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + var metadata = GetDropboxItems(parentId, true) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + + return metadata == null + ? null + : ToFolder(metadata.AsFolder); + } + + public Folder GetRootFolderByFile(string fileId) + { + return GetRootFolder(fileId); + } + + public List> GetFolders(string parentId) + { + return GetDropboxItems(parentId, true).Select(item => ToFolder(item.AsFolder)).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); //TODO:!!! + + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateBy) : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.ModifiedOn) : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateOn) : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + + while (folderId != null) + { + var dropboxFolder = GetDropboxFolder(folderId); + + if (dropboxFolder is ErrorFolder) + { + folderId = null; + } + else + { + path.Add(ToFolder(dropboxFolder)); + folderId = GetParentFolderPath(dropboxFolder); + } + } + + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + if (folder == null) throw new ArgumentNullException("folder"); + if (folder.ID != null) + { + return RenameFolder(folder, folder.Title); + } + + if (folder.ParentFolderID != null) + { + var dropboxFolderPath = MakeDropboxPath(folder.ParentFolderID); + + folder.Title = GetAvailableTitle(folder.Title, dropboxFolderPath, IsExist); + + var dropboxFolder = DropboxProviderInfo.Storage.CreateFolder(folder.Title, dropboxFolderPath); + + DropboxProviderInfo.CacheReset(dropboxFolder); + var parentFolderPath = GetParentFolderPath(dropboxFolder); + if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + + return MakeId(dropboxFolder); + } + return null; + } + + public bool IsExist(string title, string folderId) + { + return GetDropboxItems(folderId, true) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public void DeleteFolder(string folderId) + { + var dropboxFolder = GetDropboxFolder(folderId); + var id = MakeId(dropboxFolder); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(dropboxFolder is ErrorFolder)) + DropboxProviderInfo.Storage.DeleteItem(dropboxFolder); + + DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), true); + var parentFolderPath = GetParentFolderPath(dropboxFolder); + if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var dropboxFolder = GetDropboxFolder(folderId); + if (dropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)dropboxFolder).Error); + + var toDropboxFolder = GetDropboxFolder(toFolderId); + if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); + + var fromFolderPath = GetParentFolderPath(dropboxFolder); + + dropboxFolder = DropboxProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); + + DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), false); + DropboxProviderInfo.CacheReset(fromFolderPath); + DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + + return MakeId(dropboxFolder); + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var dropboxFolder = GetDropboxFolder(folderId); + if (dropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)dropboxFolder).Error); + + var toDropboxFolder = GetDropboxFolder(toFolderId); + if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); + + var newDropboxFolder = DropboxProviderInfo.Storage.CopyFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); + + DropboxProviderInfo.CacheReset(newDropboxFolder); + DropboxProviderInfo.CacheReset(MakeDropboxPath(newDropboxFolder), false); + DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + + return ToFolder(newDropboxFolder); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var dropboxFolder = GetDropboxFolder(folder.ID); + var parentFolderPath = GetParentFolderPath(dropboxFolder); + + if (IsRoot(dropboxFolder)) + { + //It's root folder + DropboxDaoSelector.RenameProvider(DropboxProviderInfo, newTitle); + //rename provider customer title + } + else + { + newTitle = GetAvailableTitle(newTitle, parentFolderPath, IsExist); + + //rename folder + dropboxFolder = DropboxProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), parentFolderPath, newTitle); + } + + DropboxProviderInfo.CacheReset(dropboxFolder); + if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + + return MakeId(dropboxFolder); + } + + public int GetItemsCount(string folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(string folderId) + { + var dropboxFolderPath = MakeDropboxPath(folderId); + //note: without cache + return DropboxProviderInfo.Storage.GetItems(dropboxFolderPath).Count == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return false; + } + + public bool CanCalculateSubitems(string entryId) + { + return false; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var storageMaxUploadSize = DropboxProviderInfo.Storage.MaxChunkedUploadFileSize; + + return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs new file mode 100644 index 0000000000..324846e336 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -0,0 +1,282 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +using ASC.Common.Caching; +using ASC.FederatedLogin; +using ASC.Files.Core; + +using Dropbox.Api.Files; + +namespace ASC.Files.Thirdparty.Dropbox +{ + [DebuggerDisplay("{CustomerTitle}")] + internal class DropboxProviderInfo : IProviderInfo, IDisposable + { + public OAuth20Token Token { get; set; } + + internal DropboxStorage Storage + { + get + { + if (Wrapper.Storage == null || !Wrapper.Storage.IsOpened) + { + return Wrapper.CreateStorage(Token); + } + return Wrapper.Storage; + } + } + + internal bool StorageOpened + { + get + { + return Wrapper.Storage != null && Wrapper.Storage.IsOpened; + } + } + + public StorageDisposableWrapper Wrapper { get; } + public DropboxProviderInfoHelper DropboxProviderInfoHelper { get; } + public int ID { get; set; } + + public Guid Owner { get; set; } + + public string CustomerTitle { get; set; } + + public DateTime CreateOn { get; set; } + + public object RootFolderId + { + get { return "dropbox-" + ID; } + } + + public string ProviderKey { get; set; } + + public FolderType RootFolderType { get; set; } + + + public DropboxProviderInfo( + StorageDisposableWrapper wrapper, + DropboxProviderInfoHelper dropboxProviderInfoHelper + ) + { + Wrapper = wrapper; + DropboxProviderInfoHelper = dropboxProviderInfoHelper; + } + + public void Dispose() + { + if (StorageOpened) + Storage.Close(); + } + + public bool CheckAccess() + { + try + { + Storage.GetUsedSpace(); + } + catch (AggregateException) + { + return false; + } + return true; + } + + public void InvalidateStorage() + { + if (Wrapper != null) + { + Wrapper.Dispose(); + } + + CacheReset(); + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + + internal FolderMetadata GetDropboxFolder(string dropboxFolderPath) + { + return DropboxProviderInfoHelper.GetDropboxFolder(Storage, ID, dropboxFolderPath); + } + + internal FileMetadata GetDropboxFile(string dropboxFilePath) + { + return DropboxProviderInfoHelper.GetDropboxFile(Storage, ID, dropboxFilePath); + } + + internal List GetDropboxItems(string dropboxFolderPath) + { + return DropboxProviderInfoHelper.GetDropboxItems(Storage, ID, dropboxFolderPath); + } + + internal void CacheReset(Metadata dropboxItem) + { + DropboxProviderInfoHelper.CacheReset(ID, dropboxItem); + } + + internal void CacheReset(string dropboxPath = null, bool? isFile = null) + { + DropboxProviderInfoHelper.CacheReset(ID, dropboxPath, isFile); + } + } + + internal class StorageDisposableWrapper : IDisposable + { + public DropboxStorage Storage { get; private set; } + + + public StorageDisposableWrapper() + { + } + + public DropboxStorage CreateStorage(OAuth20Token token) + { + if (Storage != null) return Storage; + + var dropboxStorage = new DropboxStorage(); + dropboxStorage.Open(token); + return Storage = dropboxStorage; + } + + public void Dispose() + { + Storage?.Close(); + } + } + + public class DropboxProviderInfoHelper + { + private readonly TimeSpan CacheExpiration; + private readonly ICache CacheFile; + private readonly ICache CacheFolder; + private readonly ICache CacheChildItems; + private readonly ICacheNotify CacheNotify; + + public DropboxProviderInfoHelper(ICacheNotify cacheNotify) + { + CacheExpiration = TimeSpan.FromMinutes(1); + CacheFile = AscCache.Memory; + CacheFolder = AscCache.Memory; + CacheChildItems = AscCache.Memory; + CacheNotify = cacheNotify; + + CacheNotify.Subscribe((i) => + { + if (i.ResetAll) + { + CacheFile.Remove(new Regex("^dropboxf-" + i.Key + ".*")); + CacheFolder.Remove(new Regex("^dropboxd-" + i.Key + ".*")); + CacheChildItems.Remove(new Regex("^dropbox-" + i.Key + ".*")); + } + + if (!i.IsFileExists) + { + CacheChildItems.Remove("dropbox-" + i.Key); + + CacheFolder.Remove("dropboxd-" + i.Key); + } + else + { + if (i.IsFileExists) + { + CacheFile.Remove("dropboxf-" + i.Key); + } + else + { + CacheFolder.Remove("dropboxd-" + i.Key); + } + } + }, CacheNotifyAction.Remove); + } + + internal FolderMetadata GetDropboxFolder(DropboxStorage storage, int id, string dropboxFolderPath) + { + var folder = CacheFolder.Get("dropboxd-" + id + "-" + dropboxFolderPath); + if (folder == null) + { + folder = storage.GetFolder(dropboxFolderPath); + if (folder != null) + CacheFolder.Insert("dropboxd-" + id + "-" + dropboxFolderPath, folder, DateTime.UtcNow.Add(CacheExpiration)); + } + return folder; + } + + internal FileMetadata GetDropboxFile(DropboxStorage storage, int id, string dropboxFilePath) + { + var file = CacheFile.Get("dropboxf-" + id + "-" + dropboxFilePath); + if (file == null) + { + file = storage.GetFile(dropboxFilePath); + if (file != null) + CacheFile.Insert("dropboxf-" + id + "-" + dropboxFilePath, file, DateTime.UtcNow.Add(CacheExpiration)); + } + return file; + } + + internal List GetDropboxItems(DropboxStorage storage, int id, string dropboxFolderPath) + { + var items = CacheChildItems.Get>("dropbox-" + id + "-" + dropboxFolderPath); + + if (items == null) + { + items = storage.GetItems(dropboxFolderPath); + CacheChildItems.Insert("dropbox-" + id + "-" + dropboxFolderPath, items, DateTime.UtcNow.Add(CacheExpiration)); + } + return items; + } + + internal void CacheReset(int id, Metadata dropboxItem) + { + if (dropboxItem != null) + { + CacheNotify.Publish(new DropboxCacheItem { IsFile = dropboxItem.AsFolder != null, Key = id + "-" + dropboxItem.PathDisplay }, CacheNotifyAction.Remove); + } + } + + internal void CacheReset(int id, string dropboxPath = null, bool? isFile = null) + { + var key = id + "-"; + if (dropboxPath == null) + { + CacheNotify.Publish(new DropboxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove); + } + else + { + key += dropboxPath; + + CacheNotify.Publish(new DropboxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove); + } + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs new file mode 100644 index 0000000000..788ecf616b --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs @@ -0,0 +1,99 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxSecurityDao : DropboxDaoBase, ISecurityDao + { + public DropboxSecurityDao(IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public DropboxSecurityDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + : base(dropboxInfo, dropboxDaoSelector) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxStorage.cs new file mode 100644 index 0000000000..64e4855a1c --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -0,0 +1,219 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using ASC.FederatedLogin; +using Dropbox.Api; +using Dropbox.Api.Files; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxStorage + { + private OAuth20Token _token; + + private DropboxClient _dropboxClient; + + public bool IsOpened { get; private set; } + + public long MaxChunkedUploadFileSize = 20L*1024L*1024L*1024L; + + public void Open(OAuth20Token token) + { + if (IsOpened) + return; + + _token = token; + + _dropboxClient = new DropboxClient(_token.AccessToken); + + IsOpened = true; + } + + public void Close() + { + _dropboxClient.Dispose(); + + IsOpened = false; + } + + + + public string MakeDropboxPath(string parentPath, string name) + { + return (parentPath ?? "") + "/" + (name ?? ""); + } + + public long GetUsedSpace() + { + return (long)_dropboxClient.Users.GetSpaceUsageAsync().Result.Used; + } + + public FolderMetadata GetFolder(string folderPath) + { + if (string.IsNullOrEmpty(folderPath) || folderPath == "/") + { + return new FolderMetadata(string.Empty, "/"); + } + try + { + return _dropboxClient.Files.GetMetadataAsync(folderPath).Result.AsFolder; + } + catch (AggregateException ex) + { + if (ex.InnerException is ApiException + && ex.InnerException.Message.StartsWith("path/not_found/")) + { + return null; + } + throw; + } + } + + public FileMetadata GetFile(string filePath) + { + if (string.IsNullOrEmpty(filePath) || filePath == "/") + { + return null; + } + try + { + return _dropboxClient.Files.GetMetadataAsync(filePath).Result.AsFile; + } + catch (AggregateException ex) + { + if (ex.InnerException is ApiException + && ex.InnerException.Message.StartsWith("path/not_found/")) + { + return null; + } + throw; + } + } + + public List GetItems(string folderPath) + { + return new List(_dropboxClient.Files.ListFolderAsync(folderPath).Result.Entries); + } + + public Stream DownloadStream(string filePath, int offset = 0) + { + if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("file"); + + using (var response = _dropboxClient.Files.DownloadAsync(filePath).Result) + { + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + using (var str = response.GetContentAsStreamAsync().Result) + { + if (str != null) + { + str.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(offset, SeekOrigin.Begin); + } + } + return tempBuffer; + } + } + + public FolderMetadata CreateFolder(string title, string parentPath) + { + var path = MakeDropboxPath(parentPath, title); + var result = _dropboxClient.Files.CreateFolderV2Async(path, true).Result; + return result.Metadata; + } + + public FileMetadata CreateFile(Stream fileStream, string title, string parentPath) + { + var path = MakeDropboxPath(parentPath, title); + return _dropboxClient.Files.UploadAsync(path, WriteMode.Add.Instance, true, body: fileStream).Result; + } + + public void DeleteItem(Metadata dropboxItem) + { + _dropboxClient.Files.DeleteV2Async(dropboxItem.PathDisplay).Wait(); + } + + public FolderMetadata MoveFolder(string dropboxFolderPath, string dropboxFolderPathTo, string folderName) + { + var pathTo = MakeDropboxPath(dropboxFolderPathTo, folderName); + var result = _dropboxClient.Files.MoveV2Async(dropboxFolderPath, pathTo, autorename: true).Result; + return (FolderMetadata)result.Metadata; + } + + public FileMetadata MoveFile(string dropboxFilePath, string dropboxFolderPathTo, string fileName) + { + var pathTo = MakeDropboxPath(dropboxFolderPathTo, fileName); + var result = _dropboxClient.Files.MoveV2Async(dropboxFilePath, pathTo, autorename: true).Result; + return (FileMetadata)result.Metadata; + } + + public FolderMetadata CopyFolder(string dropboxFolderPath, string dropboxFolderPathTo, string folderName) + { + var pathTo = MakeDropboxPath(dropboxFolderPathTo, folderName); + var result = _dropboxClient.Files.CopyV2Async(dropboxFolderPath, pathTo, autorename: true).Result; + return (FolderMetadata)result.Metadata; + } + + public FileMetadata CopyFile(string dropboxFilePath, string dropboxFolderPathTo, string fileName) + { + var pathTo = MakeDropboxPath(dropboxFolderPathTo, fileName); + var result = _dropboxClient.Files.CopyV2Async(dropboxFilePath, pathTo, autorename: true).Result; + return (FileMetadata)result.Metadata; + } + + public FileMetadata SaveStream(string filePath, Stream fileStream) + { + return _dropboxClient.Files.UploadAsync(filePath, WriteMode.Overwrite.Instance, body: fileStream).Result.AsFile; + } + + public string CreateResumableSession() + { + return _dropboxClient.Files.UploadSessionStartAsync(body: new MemoryStream()).Result.SessionId; + } + + public void Transfer(string dropboxSession, long offset, Stream stream) + { + _dropboxClient.Files.UploadSessionAppendV2Async(new UploadSessionCursor(dropboxSession, (ulong)offset), body: stream).Wait(); + } + + public Metadata FinishResumableSession(string dropboxSession, string dropboxFolderPath, string fileName, long offset) + { + var dropboxFilePath = MakeDropboxPath(dropboxFolderPath, fileName); + return FinishResumableSession(dropboxSession, dropboxFilePath, offset); + } + + public Metadata FinishResumableSession(string dropboxSession, string dropboxFilePath, long offset) + { + return _dropboxClient.Files.UploadSessionFinishAsync( + new UploadSessionCursor(dropboxSession, (ulong)offset), + new CommitInfo(dropboxFilePath, WriteMode.Overwrite.Instance), + new MemoryStream()).Result; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs new file mode 100644 index 0000000000..2b63dc2237 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs @@ -0,0 +1,182 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +using ASC.Files.Core; +using ASC.Files.Core.EF; + +namespace ASC.Files.Thirdparty.Dropbox +{ + internal class DropboxTagDao : DropboxDaoBase, ITagDao + { + public DropboxTagDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + : base(dropboxInfo, dropboxDaoSelector) + { + } + + #region ITagDao Members + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + var folderId = DropboxDaoSelector.ConvertId(parentFolder.ID); + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + //TODO + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(GetChildren(folderId)); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return null; + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return null; + } + + public IEnumerable SaveTags(Tag tag) + { + return null; + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return null; + } + + public void MarkAsNew(Guid subject, FileEntry fileEntry) + { + } + + #endregion + + public class TagLink + { + public int TenantId { get; set; } + public int Id { get; set; } + } + + public class TagLinkComparer : IEqualityComparer + { + 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(); + } + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs new file mode 100644 index 0000000000..d6a428eb63 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs @@ -0,0 +1,42 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using ASC.Files.Core; +using ASC.Files.Core.Security; + +namespace ASC.Files.Thirdparty +{ + internal interface IDaoSelector + { + bool IsMatch(string id); + IFileDao GetFileDao(string id); + IFolderDao GetFolderDao(string id); + ISecurityDao GetSecurityDao(string id); + ITagDao GetTagDao(string id); + string ConvertId(string id); + string GetIdCode(string id); + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs new file mode 100644 index 0000000000..67231d4f28 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -0,0 +1,579 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.Configuration; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Security.Cryptography; +using ASC.Web.Files.Classes; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +using static ASC.Files.Core.Data.AbstractDao; + +namespace ASC.Files.Thirdparty +{ + public enum ProviderTypes + { + Box, + BoxNet, + DropBox, + DropboxV2, + Google, + GoogleDrive, + OneDrive, + SharePoint, + SkyDrive, + WebDav, + Yandex, + } + + internal class ProviderAccountDao : IProviderDao + { + protected int TenantID { get; private set; } + public FilesDbContext FilesDbContext { get; } + public ILog Logger { get; } + public IServiceProvider ServiceProvider { get; } + public TenantUtil TenantUtil { get; } + public InstanceCrypto InstanceCrypto { get; } + public SecurityContext SecurityContext { get; } + public ConsumerFactory ConsumerFactory { get; } + + public ProviderAccountDao( + IServiceProvider serviceProvider, + TenantUtil tenantUtil, + TenantManager tenantManager, + InstanceCrypto instanceCrypto, + SecurityContext securityContext, + ConsumerFactory consumerFactory, + DbContextManager dbContextManager, + IOptionsMonitor options) + { + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + Logger = options.Get("ASC.Files"); + ServiceProvider = serviceProvider; + TenantUtil = tenantUtil; + InstanceCrypto = instanceCrypto; + SecurityContext = securityContext; + ConsumerFactory = consumerFactory; + } + + public virtual IProviderInfo GetProviderInfo(int linkId) + { + return GetProvidersInfoInternal(linkId).Single(); + } + + public virtual List GetProvidersInfo() + { + return GetProvidersInfoInternal(); + } + + public virtual List GetProvidersInfo(FolderType folderType, string searchText = null) + { + return GetProvidersInfoInternal(folderType: folderType, searchText: searchText); + } + + public virtual List GetProvidersInfo(Guid userId) + { + try + { + return FilesDbContext.ThirdpartyAccount + .Where(r => r.TenantId == TenantID) + .Where(r => r.UserId == userId) + .ToList() + .Select(ToProviderInfo) + .ToList(); + } + catch (Exception e) + { + Logger.Error(string.Format("GetProvidersInfoInternal: user = {0}", userId), e); + return new List(); + } + } + + private List GetProvidersInfoInternal(int linkId = -1, FolderType folderType = FolderType.DEFAULT, string searchText = null) + { + var querySelect = FilesDbContext.ThirdpartyAccount.Where(r => r.TenantId == TenantID); + + if (folderType == FolderType.USER || folderType == FolderType.DEFAULT && linkId == -1) + { + querySelect = querySelect.Where(r => r.UserId == SecurityContext.CurrentAccount.ID); + } + + if (linkId != -1) + { + querySelect = querySelect.Where(r => r.Id == linkId); + } + + if (folderType != FolderType.DEFAULT) + { + querySelect = querySelect.Where(r => r.FolderType == folderType); + } + + if (!string.IsNullOrEmpty(searchText)) + { + querySelect = querySelect.Where(r => BuildSearch(r, searchText, SearhTypeEnum.Any)); + } + + try + { + return querySelect.ToList() + .Select(ToProviderInfo) + .ToList(); + } + catch (Exception e) + { + Logger.Error(string.Format("GetProvidersInfoInternal: linkId = {0} , folderType = {1} , user = {2}", + linkId, folderType, SecurityContext.CurrentAccount.ID), e); + return new List(); + } + } + + public virtual int SaveProviderInfo(string providerKey, string customerTitle, AuthData authData, FolderType folderType) + { + ProviderTypes prKey; + try + { + prKey = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), providerKey, true); + } + catch (Exception) + { + throw new ArgumentException("Unrecognize ProviderType"); + } + + authData = GetEncodedAccesToken(authData, prKey); + + if (!CheckProviderInfo(ToProviderInfo(0, prKey, customerTitle, authData, SecurityContext.CurrentAccount.ID, folderType, TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())))) + { + throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, providerKey)); + } + var dbFilesThirdpartyAccount = new DbFilesThirdpartyAccount + { + Id = 0, + TenantId = TenantID, + Provider = providerKey, + Title = Global.ReplaceInvalidCharsAndTruncate(customerTitle), + UserName = authData.Login ?? "", + Password = EncryptPassword(authData.Password), + FolderType = folderType, + CreateOn = TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()), + UserId = SecurityContext.CurrentAccount.ID, + Token = EncryptPassword(authData.Token ?? ""), + Url = authData.Url ?? "" + }; + + return FilesDbContext.AddOrUpdate(r => r.ThirdpartyAccount, dbFilesThirdpartyAccount).Id; + } + + public bool CheckProviderInfo(IProviderInfo providerInfo) + { + return providerInfo != null && providerInfo.CheckAccess(); + } + + public virtual int UpdateProviderInfo(int linkId, AuthData authData) + { + var forUpdate = FilesDbContext.ThirdpartyAccount + .Where(r => r.Id == linkId) + .Where(r => r.TenantId == TenantID) + .ToList(); + + foreach (var f in forUpdate) + { + f.UserName = authData.Login ?? ""; + f.Password = EncryptPassword(authData.Password); + f.Token = EncryptPassword(authData.Token ?? ""); + f.Url = authData.Url ?? ""; + } + + FilesDbContext.SaveChanges(); + + return forUpdate.Count == 1 ? linkId : default; + } + + public virtual int UpdateProviderInfo(int linkId, string customerTitle, AuthData newAuthData, FolderType folderType, Guid? userId = null) + { + var authData = new AuthData(); + if (newAuthData != null && !newAuthData.IsEmpty()) + { + var querySelect = + FilesDbContext.ThirdpartyAccount + .Where(r => r.TenantId == TenantID) + .Where(r => r.Id == linkId); + + DbFilesThirdpartyAccount input; + try + { + input = querySelect.Single(); + } + catch (Exception e) + { + Logger.Error(string.Format("UpdateProviderInfo: linkId = {0} , user = {1}", linkId, SecurityContext.CurrentAccount.ID), e); + throw; + } + + if (!Enum.TryParse(input.Provider, true, out ProviderTypes key)) + { + throw new ArgumentException("Unrecognize ProviderType"); + } + + authData = new AuthData( + !string.IsNullOrEmpty(newAuthData.Url) ? newAuthData.Url : input.Url, + input.UserName, + !string.IsNullOrEmpty(newAuthData.Password) ? newAuthData.Password : DecryptPassword(input.Password), + newAuthData.Token); + + if (!string.IsNullOrEmpty(newAuthData.Token)) + { + authData = GetEncodedAccesToken(authData, key); + } + + if (!CheckProviderInfo(ToProviderInfo(0, key, customerTitle, authData, SecurityContext.CurrentAccount.ID, folderType, TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())))) + throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, key)); + } + + var toUpdate = FilesDbContext.ThirdpartyAccount + .Where(r => r.Id == linkId) + .Where(r => r.TenantId == TenantID) + .ToList(); + + foreach (var t in toUpdate) + { + if (!string.IsNullOrEmpty(customerTitle)) + { + t.Title = customerTitle; + } + + if (folderType != FolderType.DEFAULT) + { + t.FolderType = folderType; + } + + if (userId.HasValue) + { + t.UserId = userId.Value; + } + + if (!authData.IsEmpty()) + { + t.UserName = authData.Login ?? ""; + t.Password = EncryptPassword(authData.Password); + t.Token = EncryptPassword(authData.Token ?? ""); + t.Url = authData.Url ?? ""; + } + } + + FilesDbContext.SaveChanges(); + return toUpdate.Count == 1 ? linkId : default; + } + + public virtual void RemoveProviderInfo(int linkId) + { + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var folderId = GetProviderInfo(linkId).RootFolderId.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.TenantId == TenantID) + .Where(r => r.Id.StartsWith(folderId)) + .Select(r => r.HashId) + .ToList(); + + var forDelete = FilesDbContext.Security + .Where(r => r.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.EntryId)) + .ToList(); + + FilesDbContext.Security.RemoveRange(forDelete); + FilesDbContext.SaveChanges(); + + var linksForDelete = FilesDbContext.TagLink + .Where(r => r.TenantId == TenantID) + .Where(r => entryIDs.Any(e => e == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(linksForDelete); + FilesDbContext.SaveChanges(); + + var accountsForDelete = FilesDbContext.ThirdpartyAccount + .Where(r => r.Id == linkId) + .Where(r => r.TenantId == TenantID) + .ToList(); + + FilesDbContext.ThirdpartyAccount.RemoveRange(accountsForDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + } + + private IProviderInfo ToProviderInfo(int id, ProviderTypes providerKey, string customerTitle, AuthData authData, Guid owner, FolderType type, DateTime createOn) + { + var dbFilesThirdpartyAccount = new DbFilesThirdpartyAccount + { + Id = id, + Title = customerTitle, + Token = EncryptPassword(authData.Token), + Password = EncryptPassword(authData.Password), + UserId = owner, + FolderType = type, + CreateOn = createOn, + Provider = providerKey.ToString() + }; + + return ToProviderInfo(dbFilesThirdpartyAccount); + } + + private IProviderInfo ToProviderInfo(DbFilesThirdpartyAccount input) + { + if (!Enum.TryParse(input.Provider, true, out ProviderTypes key)) return null; + + var id = input.Id; + var providerTitle = input.Title ?? string.Empty; + var token = DecryptToken(input.Token); + var owner = input.UserId; + var folderType = input.FolderType; + var createOn = TenantUtil.DateTimeFromUtc(input.CreateOn); + + //if (key == ProviderTypes.Box) + //{ + // return new BoxProviderInfo( + // id, + // key.ToString(), + // providerTitle, + // token, + // owner, + // folderType, + // createOn); + //} + + if (key == ProviderTypes.DropboxV2) + { + if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null"); + + var drop = ServiceProvider.GetService(); + drop.ID = id; + drop.CustomerTitle = providerTitle; + drop.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + drop.ProviderKey = input.Provider; + drop.RootFolderType = folderType; + drop.CreateOn = createOn; + drop.Token = OAuth20Token.FromJson(token); + + return drop; + } + + //if (key == ProviderTypes.SharePoint) + //{ + // return new SharePointProviderInfo( + // id, + // key.ToString(), + // providerTitle, + // new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token), + // owner, + // folderType, + // createOn); + //} + + //if (key == ProviderTypes.GoogleDrive) + //{ + // return new GoogleDriveProviderInfo( + // id, + // key.ToString(), + // providerTitle, + // token, + // owner, + // folderType, + // createOn); + //} + + //if (key == ProviderTypes.OneDrive) + //{ + // return new OneDriveProviderInfo( + // id, + // key.ToString(), + // providerTitle, + // token, + // owner, + // folderType, + // createOn); + //} + + //return new SharpBoxProviderInfo( + // id, + // key.ToString(), + // providerTitle, + // new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token), + // owner, + // folderType, + // createOn); + + return null; + } + + private AuthData GetEncodedAccesToken(AuthData authData, ProviderTypes provider) + { + switch (provider) + { + //case ProviderTypes.GoogleDrive: + + // var code = authData.Token; + + // var token = OAuth20TokenHelper.GetAccessToken(code); + + // if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + // return new AuthData(token: token.ToJson()); + + //case ProviderTypes.Box: + + // code = authData.Token; + + // token = OAuth20TokenHelper.GetAccessToken(code); + + // if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + // return new AuthData(token: token.ToJson()); + + case ProviderTypes.DropboxV2: + + var code = authData.Token; + + var token = OAuth20TokenHelper.GetAccessToken(ConsumerFactory, code); + + if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + return new AuthData(token: token.ToJson()); + + //case ProviderTypes.DropBox: + + // var dropBoxRequestToken = DropBoxRequestToken.Parse(authData.Token); + + // var config = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.DropBox); + // var accessToken = DropBoxStorageProviderTools.ExchangeDropBoxRequestTokenIntoAccessToken(config as DropBoxConfiguration, + // ThirdpartyConfiguration.DropboxAppKey, + // ThirdpartyConfiguration.DropboxAppSecret, + // dropBoxRequestToken); + + // var base64Token = new CloudStorage().SerializeSecurityTokenToBase64Ex(accessToken, config.GetType(), new Dictionary()); + + // return new AuthData(token: base64Token); + + //case ProviderTypes.OneDrive: + + // code = authData.Token; + + // token = OAuth20TokenHelper.GetAccessToken(code); + + // if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + // return new AuthData(token: token.ToJson()); + + //case ProviderTypes.SkyDrive: + + // code = authData.Token; + + // token = OAuth20TokenHelper.GetAccessToken(code); + + // if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + // accessToken = AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20.OAuth20Token.FromJson(token.ToJson()); + + // if (accessToken == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider)); + + // config = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.SkyDrive); + // var storage = new CloudStorage(); + // base64Token = storage.SerializeSecurityTokenToBase64Ex(accessToken, config.GetType(), new Dictionary()); + + // return new AuthData(token: base64Token); + + //case ProviderTypes.SharePoint: + //case ProviderTypes.WebDav: + // break; + + default: + authData.Url = null; + break; + } + + return authData; + } + + private string EncryptPassword(string password) + { + return string.IsNullOrEmpty(password) ? string.Empty : InstanceCrypto.Encrypt(password); + } + + private string DecryptPassword(string password) + { + return string.IsNullOrEmpty(password) ? string.Empty : InstanceCrypto.Decrypt(password); + } + + private string DecryptToken(string token) + { + try + { + return DecryptPassword(token); + } + catch + { + //old token in base64 without encrypt + return token ?? ""; + } + } + } + + public static class ProviderAccountDaoExtention + { + public static DIHelper AddProviderAccountDaoService(this DIHelper services) + { + //services.TryAddScoped(); + + return services + .AddTenantUtilService() + .AddTenantManagerService() + .AddInstanceCryptoService() + .AddSecurityContextService() + .AddConsumerFactoryService() + .AddDbContextManagerService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs new file mode 100644 index 0000000000..c6b03cc0c9 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -0,0 +1,251 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Files.Thirdparty.Dropbox; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.ProviderDao +{ + internal class ProviderDaoBase + { + private readonly List Selectors; + + public ProviderDaoBase(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + Selectors = new List + { + + //Fill in selectors + //Selectors.Add(Default); //Legacy DB dao + //Selectors.Add(new SharpBoxDaoSelector()); + //Selectors.Add(new SharePointDaoSelector()); + //Selectors.Add(new GoogleDriveDaoSelector()); + //Selectors.Add(new BoxDaoSelector()); + ServiceProvider.GetService() + }; + // Selectors.Add(new OneDriveDaoSelector()); + } + + public IServiceProvider ServiceProvider { get; } + + //protected bool IsCrossDao(object id1, object id2) + //{ + // if (id2 == null || id1 == null) + // return false; + // return !Equals(GetSelector(id1).GetIdCode(id1), GetSelector(id2).GetIdCode(id2)); + //} + + protected IDaoSelector GetSelector(string id) + { + return Selectors.FirstOrDefault(selector => selector.IsMatch(id)); + } + + //protected void SetSharedProperty(IEnumerable> entries) + //{ + // using (var securityDao = TryGetSecurityDao()) + // { + // securityDao.GetPureShareRecords(entries.ToArray()) + // //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) + // .Select(x => x.EntryId).Distinct().ToList() + // .ForEach(id => + // { + // var firstEntry = entries.FirstOrDefault(y => y.ID.Equals(id)); + + // if (firstEntry != null) + // firstEntry.Shared = true; + // }); + // } + //} + + protected IEnumerable GetSelectors() + { + return Selectors; + } + + + //protected File PerformCrossDaoFileCopy(object fromFileId, object toFolderId, bool deleteSourceFile) + //{ + // var fromSelector = GetSelector(fromFileId); + // var toSelector = GetSelector(toFolderId); + // //Get File from first dao + // var fromFileDao = fromSelector.GetFileDao(fromFileId); + // var toFileDao = toSelector.GetFileDao(toFolderId); + // var fromFile = fromFileDao.GetFile(fromSelector.ConvertId(fromFileId)); + + // if (fromFile.ContentLength > SetupInfo.AvailableFileSize) + // { + // throw new Exception(string.Format(deleteSourceFile ? FilesCommonResource.ErrorMassage_FileSizeMove : FilesCommonResource.ErrorMassage_FileSizeCopy, + // FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); + // } + + // using (var securityDao = TryGetSecurityDao()) + // using (var tagDao = TryGetTagDao()) + // { + // var fromFileShareRecords = securityDao.GetPureShareRecords(fromFile).Where(x => x.EntryType == FileEntryType.File); + // var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFile).ToList(); + // var fromFileLockTag = tagDao.GetTags(fromFile.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); + + // var toFile = new File + // { + // Title = fromFile.Title, + // Encrypted = fromFile.Encrypted, + // FolderID = toSelector.ConvertId(toFolderId) + // }; + + // fromFile.ID = fromSelector.ConvertId(fromFile.ID); + + // var mustConvert = !string.IsNullOrEmpty(fromFile.ConvertedType); + // using (var fromFileStream = mustConvert + // ? FileConverter.Exec(fromFile) + // : fromFileDao.GetFileStream(fromFile)) + // { + // toFile.ContentLength = fromFileStream.CanSeek ? fromFileStream.Length : fromFile.ContentLength; + // toFile = toFileDao.SaveFile(toFile, fromFileStream); + // } + + // if (deleteSourceFile) + // { + // if (fromFileShareRecords.Any()) + // fromFileShareRecords.ToList().ForEach(x => + // { + // x.EntryId = toFile.ID; + // securityDao.SetShare(x); + // }); + + // var fromFileTags = fromFileNewTags; + // if (fromFileLockTag != null) fromFileTags.Add(fromFileLockTag); + + // if (fromFileTags.Any()) + // { + // fromFileTags.ForEach(x => x.EntryId = toFile.ID); + + // tagDao.SaveTags(fromFileTags); + // } + + // //Delete source file if needed + // fromFileDao.DeleteFile(fromSelector.ConvertId(fromFileId)); + // } + // return toFile; + // } + //} + + //protected Folder PerformCrossDaoFolderCopy(object fromFolderId, object toRootFolderId, bool deleteSourceFolder, CancellationToken? cancellationToken) + //{ + // //Things get more complicated + // var fromSelector = GetSelector(fromFolderId); + // var toSelector = GetSelector(toRootFolderId); + + // var fromFolderDao = fromSelector.GetFolderDao(fromFolderId); + // var fromFileDao = fromSelector.GetFileDao(fromFolderId); + // //Create new folder in 'to' folder + // var toFolderDao = toSelector.GetFolderDao(toRootFolderId); + // //Ohh + // var fromFolder = fromFolderDao.GetFolder(fromSelector.ConvertId(fromFolderId)); + + // var toFolder = toFolderDao.GetFolder(fromFolder.Title, toSelector.ConvertId(toRootFolderId)); + // var toFolderId = toFolder != null + // ? toFolder.ID + // : toFolderDao.SaveFolder( + // new Folder + // { + // Title = fromFolder.Title, + // ParentFolderID = toSelector.ConvertId(toRootFolderId) + // }); + + // var foldersToCopy = fromFolderDao.GetFolders(fromSelector.ConvertId(fromFolderId)); + // var fileIdsToCopy = fromFileDao.GetFiles(fromSelector.ConvertId(fromFolderId)); + // Exception copyException = null; + // //Copy files first + // foreach (var fileId in fileIdsToCopy) + // { + // if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + // try + // { + // PerformCrossDaoFileCopy(fileId, toFolderId, deleteSourceFolder); + // } + // catch (Exception ex) + // { + // copyException = ex; + // } + // } + // foreach (var folder in foldersToCopy) + // { + // if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + // try + // { + // PerformCrossDaoFolderCopy(folder.ID, toFolderId, deleteSourceFolder, cancellationToken); + // } + // catch (Exception ex) + // { + // copyException = ex; + // } + // } + + // if (deleteSourceFolder) + // { + // using (var securityDao = TryGetSecurityDao()) + // { + // var fromFileShareRecords = securityDao.GetPureShareRecords(fromFolder) + // .Where(x => x.EntryType == FileEntryType.Folder); + + // if (fromFileShareRecords.Any()) + // { + // fromFileShareRecords.ToList().ForEach(x => + // { + // x.EntryId = toFolderId; + // securityDao.SetShare(x); + // }); + // } + // } + + // using (var tagDao = TryGetTagDao()) + // { + // var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFolder).ToList(); + + // if (fromFileNewTags.Any()) + // { + // fromFileNewTags.ForEach(x => x.EntryId = toFolderId); + + // tagDao.SaveTags(fromFileNewTags); + // } + // } + + // if (copyException == null) + // fromFolderDao.DeleteFolder(fromSelector.ConvertId(fromFolderId)); + // } + + // if (copyException != null) throw copyException; + + // return toFolderDao.GetFolder(toSelector.ConvertId(toFolderId)); + //} + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs new file mode 100644 index 0000000000..728277a6ab --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -0,0 +1,122 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Globalization; +using System.Text.RegularExpressions; + +using ASC.Files.Core; +using ASC.Files.Core.Security; + +namespace ASC.Files.Thirdparty +{ + internal abstract class RegexDaoSelectorBase : IDaoSelector + { + public Regex Selector { get; set; } + public Func> FileDaoActivator { get; set; } + public Func> SecurityDaoActivator { get; set; } + public Func> FolderDaoActivator { get; set; } + public Func> TagDaoActivator { get; set; } + public Func IDConverter { get; set; } + + protected RegexDaoSelectorBase(Regex selector) + : this(selector, null, null, null, null) + { + } + + protected RegexDaoSelectorBase(Regex selector, + Func> fileDaoActivator, + Func> folderDaoActivator, + Func> securityDaoActivator, + Func> tagDaoActivator + ) + : this(selector, fileDaoActivator, folderDaoActivator, securityDaoActivator, tagDaoActivator, null) + { + } + + protected RegexDaoSelectorBase( + Regex selector, + Func> fileDaoActivator, + Func> folderDaoActivator, + Func> securityDaoActivator, + Func> tagDaoActivator, + Func idConverter) + { + Selector = selector ?? throw new ArgumentNullException("selector"); + FileDaoActivator = fileDaoActivator; + FolderDaoActivator = folderDaoActivator; + SecurityDaoActivator = securityDaoActivator; + TagDaoActivator = tagDaoActivator; + IDConverter = idConverter; + } + + public virtual ISecurityDao GetSecurityDao(string id) + { + return SecurityDaoActivator != null ? SecurityDaoActivator(id) : null; + } + + + public virtual string ConvertId(string id) + { + try + { + if (id == null) return null; + + return IDConverter != null ? IDConverter(id) : id; + } + catch (Exception fe) + { + throw new FormatException("Can not convert id: " + id, fe); + } + } + + public virtual string GetIdCode(string id) + { + return null; + } + + public virtual bool IsMatch(string id) + { + return id != null && Selector.IsMatch(Convert.ToString(id, CultureInfo.InvariantCulture)); + } + + + public virtual IFileDao GetFileDao(string id) + { + return FileDaoActivator != null ? FileDaoActivator(id) : null; + } + + public virtual IFolderDao GetFolderDao(string id) + { + return FolderDaoActivator != null ? FolderDaoActivator(id) : null; + } + + public virtual ITagDao GetTagDao(string id) + { + return TagDaoActivator != null ? TagDaoActivator(id) : null; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs index 15c05e1800..b8a06935cd 100644 --- a/products/ASC.Files/Server/Helpers/DocuSignHelper.cs +++ b/products/ASC.Files/Server/Helpers/DocuSignHelper.cs @@ -35,6 +35,7 @@ using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common; +using ASC.Core.Common.Configuration; using ASC.Core.Users; using ASC.FederatedLogin; using ASC.FederatedLogin.Helpers; @@ -71,18 +72,19 @@ namespace ASC.Web.Files.Helpers public const string AppAttr = "docusign"; public TokenHelper TokenHelper { get; } - public AuthContext AuthContext { get; } + public AuthContext AuthContext { get; } + public ConsumerFactory ConsumerFactory { get; } public DocuSignLoginProvider DocuSignLoginProvider { get; } public DocuSignToken( TokenHelper tokenHelper, IOptionsMonitor options, AuthContext authContext, - DocuSignLoginProvider docuSignLoginProvider) + ConsumerFactory consumerFactory) { TokenHelper = tokenHelper; - AuthContext = authContext; - DocuSignLoginProvider = docuSignLoginProvider; + AuthContext = authContext; + ConsumerFactory = consumerFactory; Log = options.CurrentValue; } @@ -111,7 +113,7 @@ namespace ASC.Web.Files.Helpers { Log.Info("DocuSign refresh token for user " + AuthContext.CurrentAccount.ID); - var refreshed = DocuSignLoginProvider.Instance.RefreshToken(token.RefreshToken); + var refreshed = ConsumerFactory.Get().RefreshToken(token.RefreshToken); if (refreshed != null) { @@ -163,8 +165,9 @@ namespace ASC.Web.Files.Helpers public GlobalFolderHelper GlobalFolderHelper { get; } public FilesMessageService FilesMessageService { get; } public FilesLinkUtility FilesLinkUtility { get; } - public IServiceProvider ServiceProvider { get; } - + public IServiceProvider ServiceProvider { get; } + public ConsumerFactory ConsumerFactory { get; } + public DocuSignHelper( DocuSignToken docuSignToken, DocuSignLoginProvider docuSignLoginProvider, @@ -179,7 +182,8 @@ namespace ASC.Web.Files.Helpers GlobalFolderHelper globalFolderHelper, FilesMessageService filesMessageService, FilesLinkUtility filesLinkUtility, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + ConsumerFactory consumerFactory) { DocuSignToken = docuSignToken; DocuSignLoginProvider = docuSignLoginProvider; @@ -193,7 +197,8 @@ namespace ASC.Web.Files.Helpers GlobalFolderHelper = globalFolderHelper; FilesMessageService = filesMessageService; FilesLinkUtility = filesLinkUtility; - ServiceProvider = serviceProvider; + ServiceProvider = serviceProvider; + ConsumerFactory = consumerFactory; Log = options.CurrentValue; } @@ -223,7 +228,7 @@ namespace ASC.Web.Files.Helpers { if (token == null) throw new ArgumentNullException("token"); - var userInfoString = RequestHelper.PerformRequest(DocuSignLoginProvider.Instance.DocuSignHost + "/oauth/userinfo", + var userInfoString = RequestHelper.PerformRequest(ConsumerFactory.Get().DocuSignHost + "/oauth/userinfo", headers: new Dictionary { { "Authorization", "Bearer " + DocuSignToken.GetRefreshedToken(token) } }); Log.Debug("DocuSing userInfo: " + userInfoString); diff --git a/products/ASC.Files/Server/Helpers/EasyBibHelper.cs b/products/ASC.Files/Server/Helpers/EasyBibHelper.cs index 773a30a003..929f084a17 100644 --- a/products/ASC.Files/Server/Helpers/EasyBibHelper.cs +++ b/products/ASC.Files/Server/Helpers/EasyBibHelper.cs @@ -72,14 +72,13 @@ namespace ASC.Web.Files.Helpers TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { Log = option.CurrentValue; } diff --git a/products/ASC.Files/Server/Helpers/ThirdpartyConfiguration.cs b/products/ASC.Files/Server/Helpers/ThirdpartyConfiguration.cs index 988caa1f15..bdb01f07c6 100644 --- a/products/ASC.Files/Server/Helpers/ThirdpartyConfiguration.cs +++ b/products/ASC.Files/Server/Helpers/ThirdpartyConfiguration.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Core.Common.Configuration; using ASC.FederatedLogin.LoginProviders; using ASC.Files.Core; using ASC.Files.Core.Data; @@ -50,19 +51,15 @@ namespace ASC.Web.Files.Helpers public ThirdpartyConfiguration( IConfiguration configuration, IDaoFactory daoFactory, - BoxLoginProvider boxLoginProvider, - DropboxLoginProvider dropboxLoginProvider, - OneDriveLoginProvider oneDriveLoginProvider, - DocuSignLoginProvider docuSignLoginProvider, - GoogleLoginProvider googleLoginProvider) + ConsumerFactory consumerFactory) { Configuration = configuration; DaoFactory = daoFactory; - BoxLoginProvider = boxLoginProvider; - DropboxLoginProvider = dropboxLoginProvider; - OneDriveLoginProvider = oneDriveLoginProvider; - DocuSignLoginProvider = docuSignLoginProvider; - GoogleLoginProvider = googleLoginProvider; + BoxLoginProvider = consumerFactory.Get(); + DropboxLoginProvider = consumerFactory.Get(); + OneDriveLoginProvider = consumerFactory.Get(); + DocuSignLoginProvider = consumerFactory.Get(); + GoogleLoginProvider = consumerFactory.Get(); } public IEnumerable ThirdPartyProviders @@ -85,7 +82,7 @@ namespace ASC.Web.Files.Helpers { get { - return ThirdPartyProviders.Contains("box") && BoxLoginProvider.Instance.IsEnabled; + return ThirdPartyProviders.Contains("box") && BoxLoginProvider.IsEnabled; } } @@ -93,7 +90,7 @@ namespace ASC.Web.Files.Helpers { get { - return ThirdPartyProviders.Contains("dropboxv2") && DropboxLoginProvider.Instance.IsEnabled; + return ThirdPartyProviders.Contains("dropboxv2") && DropboxLoginProvider.IsEnabled; } } @@ -101,7 +98,7 @@ namespace ASC.Web.Files.Helpers { get { - return ThirdPartyProviders.Contains("onedrive") && OneDriveLoginProvider.Instance.IsEnabled; + return ThirdPartyProviders.Contains("onedrive") && OneDriveLoginProvider.IsEnabled; } } @@ -132,19 +129,19 @@ namespace ASC.Web.Files.Helpers public string DropboxAppKey { - get { return DropboxLoginProvider.Instance["dropboxappkey"]; } + get { return DropboxLoginProvider["dropboxappkey"]; } } public string DropboxAppSecret { - get { return DropboxLoginProvider.Instance["dropboxappsecret"]; } + get { return DropboxLoginProvider["dropboxappsecret"]; } } public bool SupportDocuSignInclusion { get { - return ThirdPartyProviders.Contains("docusign") && DocuSignLoginProvider.Instance.IsEnabled; + return ThirdPartyProviders.Contains("docusign") && DocuSignLoginProvider.IsEnabled; } } @@ -152,7 +149,7 @@ namespace ASC.Web.Files.Helpers { get { - return ThirdPartyProviders.Contains("google") && GoogleLoginProvider.Instance.IsEnabled; + return ThirdPartyProviders.Contains("google") && GoogleLoginProvider.IsEnabled; } } } diff --git a/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs b/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs index 87aa69dfcd..9942cf2054 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/BoxApp.cs @@ -142,11 +142,10 @@ namespace ASC.Web.Files.ThirdPartyApp TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary additional) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, additional) { PathProvider = pathProvider; TenantUtil = tenantUtil; diff --git a/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs b/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs index a7edb6420b..d9218e48bd 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/GoogleDriveApp.cs @@ -152,11 +152,10 @@ namespace ASC.Web.Files.ThirdPartyApp TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary additional) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, additional) { Logger = option.CurrentValue; PathProvider = pathProvider; diff --git a/products/ASC.Files/Server/proto/DropboxCacheItem.proto b/products/ASC.Files/Server/proto/DropboxCacheItem.proto new file mode 100644 index 0000000000..9cf3a07648 --- /dev/null +++ b/products/ASC.Files/Server/proto/DropboxCacheItem.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty.Dropbox; + +message DropboxCacheItem { + bool ResetAll = 1; + bool IsFile = 2; + bool IsFileExists = 3; + string Key = 4; +} \ No newline at end of file diff --git a/products/ASC.Files/Server/proto/ProviderAccountCacheItem.proto b/products/ASC.Files/Server/proto/ProviderAccountCacheItem.proto new file mode 100644 index 0000000000..a729ba4e7c --- /dev/null +++ b/products/ASC.Files/Server/proto/ProviderAccountCacheItem.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty; + +message ProviderAccountCacheItem { + string Key = 1; +} \ No newline at end of file diff --git a/web/ASC.Web.Core/Jabber/FireBase.cs b/web/ASC.Web.Core/Jabber/FireBase.cs index 4ee0eee1c4..4080aacab4 100644 --- a/web/ASC.Web.Core/Jabber/FireBase.cs +++ b/web/ASC.Web.Core/Jabber/FireBase.cs @@ -56,11 +56,6 @@ namespace ASC.Web.Core.Jabber get { return this["firebase_messagingSenderId"]; } } - public FireBase Instance - { - get { return ConsumerFactory.Get(); } - } - public FireBase() { } @@ -69,11 +64,10 @@ namespace ASC.Web.Core.Jabber TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { } } diff --git a/web/ASC.Web.Core/Sms/SmsProvider.cs b/web/ASC.Web.Core/Sms/SmsProvider.cs index 25980a25fc..b0388980f0 100644 --- a/web/ASC.Web.Core/Sms/SmsProvider.cs +++ b/web/ASC.Web.Core/Sms/SmsProvider.cs @@ -144,12 +144,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, name, order, props, additional) { Log = options.CurrentValue; } @@ -206,12 +205,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, options, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, options, name, order, props, additional) { } @@ -343,12 +341,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, options, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, options, name, order, props, additional) { } } @@ -363,12 +360,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, options, name, order, null, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, options, name, order, null, additional) { } } @@ -432,12 +428,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary props, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, options, name, order, props, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, options, name, order, props, additional) { } @@ -481,12 +476,11 @@ namespace ASC.Web.Core.Sms TenantManager tenantManager, CoreBaseSettings coreBaseSettings, CoreSettings coreSettings, - ConsumerFactory consumerFactory, IConfiguration configuration, ICacheNotify cache, IOptionsMonitor options, string name, int order, Dictionary additional = null) - : base(tenantManager, coreBaseSettings, coreSettings, consumerFactory, configuration, cache, options, name, order, null, additional) + : base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, options, name, order, null, additional) { } } From 03bb507d865df0907378a0f9d6f6cff23466f0a9 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 10 Mar 2020 16:31:53 +0300 Subject: [PATCH 08/30] Files: added ProviderSecurityDao --- .../Server/Controllers/FilesController.cs | 4 +- .../Core/Dao/Interfaces/IProviderInfo.cs | 2 +- .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 2 + .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 1 + .../Server/Core/Dao/TeamlabDao/SecurityDao.cs | 20 +- .../Server/Core/Entries/FileEntry.cs | 64 +++--- .../Server/Core/FileStorageService.cs | 16 +- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 15 +- .../Core/Thirdparty/ProviderAccountDao.cs | 1 + .../ProviderDao/ProviderSecutiryDao.cs | 204 ++++++++++++++++++ .../Server/Model/FileEntryWrapper.cs | 40 +++- .../Server/Model/FolderContentWrapper.cs | 22 +- .../WCFService/Wrappers/DataWrapper.cs | 2 +- .../ASC.Files/Server/Utils/EntryManager.cs | 36 ++-- products/ASC.Files/Server/Utils/FileMarker.cs | 12 +- 15 files changed, 359 insertions(+), 82 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index b4a6eba053..862e3033c9 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -244,9 +244,9 @@ namespace ASC.Api.Documents /// Folders /// Shared folder contents [Read("@share")] - public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.GetFolderShare(), userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.FolderShare, userIdOrGroupId, filterType); } /// diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs index 2a5904546a..4ebe0cbfcd 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs @@ -37,7 +37,7 @@ namespace ASC.Files.Core DateTime CreateOn { get; } string CustomerTitle { get; } - object RootFolderId { get; } + string RootFolderId { get; } bool CheckAccess(); void InvalidateStorage(); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index 4f583d53dc..6dac1acd38 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -29,6 +29,7 @@ using System; using ASC.Common; using ASC.Files.Core.Security; using ASC.Files.Thirdparty; +using ASC.Files.Thirdparty.ProviderDao; using Microsoft.Extensions.DependencyInjection; @@ -76,6 +77,7 @@ namespace ASC.Files.Core.Data .AddTagDaoService() .AddSecurityDaoService() .AddCachedProviderAccountDaoService() + .AddProviderSecurityDaoService() ; } } diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index 9f8b770588..83bc453d54 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -1041,6 +1041,7 @@ namespace ASC.Files.Core.Data { services.TryAddScoped, FolderDao>(); services.TryAddTransient>(); + services.TryAddTransient>(); return services .AddFactoryIndexerService() diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs index b3c50166c5..4cbed7ca41 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/SecurityDao.cs @@ -42,7 +42,7 @@ using ASC.Web.Studio.Utility; namespace ASC.Files.Core.Data { - internal class SecurityDao : AbstractDao, ISecurityDao + internal class SecurityDao : AbstractDao, ISecurityDao { public SecurityDao(UserManager userManager, DbContextManager dbContextManager, @@ -180,7 +180,7 @@ namespace ASC.Files.Core.Data return FromQuery(q); } - public IEnumerable GetPureShareRecords(IEnumerable> entries) + public IEnumerable GetPureShareRecords(IEnumerable> entries) { if (entries == null) return new List(); @@ -195,7 +195,7 @@ namespace ASC.Files.Core.Data return GetPureShareRecordsDb(files, folders); } - public IEnumerable GetPureShareRecords(FileEntry entry) + public IEnumerable GetPureShareRecords(FileEntry entry) { if (entry == null) return new List(); @@ -228,7 +228,7 @@ namespace ASC.Files.Core.Data /// /// /// - public IEnumerable GetShares(IEnumerable> entries) + public IEnumerable GetShares(IEnumerable> entries) { if (entries == null) return new List(); @@ -248,7 +248,7 @@ namespace ASC.Files.Core.Data /// /// /// - public IEnumerable GetShares(FileEntry entry) + public IEnumerable GetShares(FileEntry entry) { if (entry == null) return new List(); @@ -259,13 +259,13 @@ namespace ASC.Files.Core.Data return SaveFilesAndFoldersForShare(files, foldersInt); } - private void SelectFilesAndFoldersForShare(FileEntry entry, ICollection files, ICollection folders, ICollection foldersInt) + private void SelectFilesAndFoldersForShare(FileEntry entry, ICollection files, ICollection folders, ICollection foldersInt) { - object folderId; + T folderId; if (entry.FileEntryType == FileEntryType.File) { var fileId = MappingID(entry.ID); - folderId = ((File)entry).FolderID; + folderId = ((File)entry).FolderID; if (!files.Contains(fileId.ToString())) files.Add(fileId.ToString()); } else @@ -369,7 +369,9 @@ namespace ASC.Files.Core.Data { public static DIHelper AddSecurityDaoService(this DIHelper services) { - services.TryAddScoped, SecurityDao>(); + services.TryAddScoped, SecurityDao>(); + services.TryAddScoped>(); + services.TryAddScoped>(); return services .AddUserManagerService() diff --git a/products/ASC.Files/Server/Core/Entries/FileEntry.cs b/products/ASC.Files/Server/Core/Entries/FileEntry.cs index 6748734040..a6210f4fca 100644 --- a/products/ASC.Files/Server/Core/Entries/FileEntry.cs +++ b/products/ASC.Files/Server/Core/Entries/FileEntry.cs @@ -32,18 +32,13 @@ using ASC.Web.Files.Classes; namespace ASC.Files.Core { - [DataContract(Name = "entry", Namespace = "")] - [Serializable] - public abstract class FileEntry : ICloneable + public abstract class FileEntry : ICloneable { public FileEntry(Global global) { Global = global; } - [DataMember(Name = "id")] - public T ID { get; set; } - [DataMember(Name = "title", IsRequired = true)] public virtual string Title { get; set; } @@ -95,14 +90,6 @@ namespace ASC.Files.Core [DataMember(Name = "provider_key", EmitDefaultValue = false)] public string ProviderKey { get; set; } - - [DataMember(Name = "folder_id")] - public abstract T FolderIdDisplay - { - get; - set; - } - public bool ProviderEntry { get { return !string.IsNullOrEmpty(ProviderKey); } @@ -116,22 +103,52 @@ namespace ASC.Files.Core public Guid RootFolderCreator { get; set; } - public T RootFolderId { get; set; } - public abstract bool IsNew { get; set; } public FileEntryType FileEntryType; - public string UniqID - { - get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } - } - public Global Global { get; } private string _modifiedByString; private string _createByString; + + public override string ToString() + { + return Title; + } + + public object Clone() + { + return MemberwiseClone(); + } + } + + [DataContract(Name = "entry", Namespace = "")] + [Serializable] + public abstract class FileEntry : FileEntry, ICloneable + { + public FileEntry(Global global) : base(global) + { + } + + [DataMember(Name = "id")] + public T ID { get; set; } + + + [DataMember(Name = "folder_id")] + public abstract T FolderIdDisplay + { + get; + set; + } + + public T RootFolderId { get; set; } + public string UniqID + { + get { return string.Format("{0}_{1}", GetType().Name.ToLower(), ID); } + } + public override bool Equals(object obj) { return obj is FileEntry f && Equals(f.ID, ID); @@ -151,10 +168,5 @@ namespace ASC.Files.Core { return Title; } - - public object Clone() - { - return MemberwiseClone(); - } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index a4aafb349c..6c40e12dcc 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -274,7 +274,7 @@ namespace ASC.Web.Files.Services.WCFService orderBy.SortedBy = SortedByType.New; int total; - IEnumerable> entries; + IEnumerable entries; try { entries = EntryManager.GetEntries(parent, from, count, filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, orderBy, out total); @@ -303,7 +303,7 @@ namespace ASC.Web.Files.Services.WCFService var result = new DataWrapper { Total = total, - Entries = new ItemList>(entries.ToList()), + Entries = new ItemList(entries.ToList()), FolderPathParts = new ItemList(breadCrumbs.Select(f => f.ID)), FolderInfo = parent, RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew() @@ -498,7 +498,7 @@ namespace ASC.Web.Files.Services.WCFService orderBy.SortedBy = SortedByType.New; } - var entries = Enumerable.Empty>(); + var entries = Enumerable.Empty(); if (!FileSecurity.CanRead(parent)) { @@ -1039,7 +1039,7 @@ namespace ASC.Web.Files.Services.WCFService var result = FileMarker.MarkedItems(folder); - result = new List>(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false))); + result = new List(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false))); if (!result.ToList().Any()) { @@ -1048,7 +1048,7 @@ namespace ASC.Web.Files.Services.WCFService var response = new HttpResponseMessage(HttpStatusCode.OK) { - Content = new StreamContent(serializer.ToXml(new ItemList>(result))) + Content = new StreamContent(serializer.ToXml(new ItemList(result))) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return response; @@ -1088,10 +1088,10 @@ namespace ASC.Web.Files.Services.WCFService return new ItemList(resultList.ToList()); } - public ItemList> GetThirdPartyFolder(int folderType = 0) + public ItemList GetThirdPartyFolder(int folderType = 0) { var providerDao = GetProviderDao(); - if (providerDao == null) return new ItemList>(); + if (providerDao == null) return new ItemList(); var providersInfo = providerDao.GetProvidersInfo((FolderType)folderType); @@ -1102,7 +1102,7 @@ namespace ASC.Web.Files.Services.WCFService return folder; }); - return new ItemList>(folders); + return new ItemList(folders); } public Folder SaveThirdParty(ThirdPartyParams thirdPartyParams) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index 324846e336..ef753ddded 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text.RegularExpressions; +using ASC.Common; using ASC.Common.Caching; using ASC.FederatedLogin; using ASC.Files.Core; @@ -72,7 +73,7 @@ namespace ASC.Files.Thirdparty.Dropbox public DateTime CreateOn { get; set; } - public object RootFolderId + public string RootFolderId { get { return "dropbox-" + ID; } } @@ -278,5 +279,17 @@ namespace ASC.Files.Thirdparty.Dropbox CacheNotify.Publish(new DropboxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove); } } + } + + public static class DropboxProviderInfoExtension + { + public static DIHelper AddDropboxProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddSingleton(); + + return services; + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index 67231d4f28..6fa8961660 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -568,6 +568,7 @@ namespace ASC.Files.Thirdparty //services.TryAddScoped(); return services + .AddDropboxProviderInfoService() .AddTenantUtilService() .AddTenantManagerService() .AddInstanceCryptoService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs new file mode 100644 index 0000000000..a39e3a2adf --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs @@ -0,0 +1,204 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Data; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.ProviderDao +{ + internal class ProviderSecurityDao : ProviderDaoBase, ISecurityDao + { + public SecurityDao SecurityDao { get; } + + public ProviderSecurityDao(IServiceProvider serviceProvider, SecurityDao securityDao) : base(serviceProvider) + { + SecurityDao = securityDao; + } + + public void SetShare(FileShareRecord r) + { + SecurityDao.SetShare(r); + } + + public IEnumerable GetShares(IEnumerable> entries) + { + var result = new List(); + + var files = entries.Where(x => x.FileEntryType == FileEntryType.File).ToArray(); + var folders = entries.Where(x => x.FileEntryType == FileEntryType.Folder).ToList(); + + if (files.Any()) + { + var folderIds = files.Select(x => ((File)x).FolderID).Distinct(); + foreach (var folderId in folderIds) + { + GetFoldersForShare(folderId, folders); + } + + var pureShareRecords = SecurityDao.GetPureShareRecords(files); + if (pureShareRecords != null) + { + foreach (var pureShareRecord in pureShareRecords) + { + if (pureShareRecord == null) continue; + pureShareRecord.Level = -1; + result.Add(pureShareRecord); + } + } + } + + result.AddRange(GetShareForFolders(folders)); + + return result; + } + + public IEnumerable GetShares(FileEntry entry) + { + var result = new List(); + + if (entry == null) return result; + + + var folders = new List>(); + if (entry is Folder entryFolder) + { + folders.Add(entryFolder); + } + + if (entry is File file) + { + GetFoldersForShare(file.FolderID, folders); + + var pureShareRecords = SecurityDao.GetPureShareRecords(entry); + if (pureShareRecords != null) + { + foreach (var pureShareRecord in pureShareRecords) + { + if (pureShareRecord == null) continue; + pureShareRecord.Level = -1; + result.Add(pureShareRecord); + } + } + } + + result.AddRange(GetShareForFolders(folders)); + + return result; + } + + private void GetFoldersForShare(string folderId, ICollection> folders) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + if (folderDao == null) return; + + var folder = folderDao.GetFolder(selector.ConvertId(folderId)); + if (folder != null) folders.Add(folder); + } + + private List GetShareForFolders(IReadOnlyCollection> folders) + { + if (!folders.Any()) return new List(); + + var result = new List(); + + foreach (var folder in folders) + { + var selector = GetSelector(folder.ID); + var folderDao = selector.GetFolderDao(folder.ID); + if (folderDao == null) continue; + + var parentFolders = folderDao.GetParentFolders(selector.ConvertId(folder.ID)); + if (parentFolders == null || !parentFolders.Any()) continue; + + parentFolders.Reverse(); + var pureShareRecords = GetPureShareRecords(parentFolders); + if (pureShareRecords == null) continue; + + foreach (var pureShareRecord in pureShareRecords) + { + if (pureShareRecord == null) continue; + var f = ServiceProvider.GetService>(); + f.ID = pureShareRecord.EntryId.ToString(); + + pureShareRecord.Level = parentFolders.IndexOf(f); + pureShareRecord.EntryId = folder.ID; + result.Add(pureShareRecord); + } + } + + return result; + } + + public void RemoveSubject(Guid subject) + { + SecurityDao.RemoveSubject(subject); + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return SecurityDao.GetShares(subjects); + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return SecurityDao.GetPureShareRecords(entries); + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return SecurityDao.GetPureShareRecords(entry); + } + + public void DeleteShareRecords(IEnumerable records) + { + SecurityDao.DeleteShareRecords(records); + } + + public bool IsShared(object entryId, FileEntryType type) + { + return SecurityDao.IsShared(entryId, type); + } + } + + public static class ProviderSecurityDaoExtention + { + public static DIHelper AddProviderSecurityDaoService(this DIHelper services) + { + services.TryAddScoped, ProviderSecurityDao>(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Model/FileEntryWrapper.cs b/products/ASC.Files/Server/Model/FileEntryWrapper.cs index f5a30bdee2..9efe3b9eab 100644 --- a/products/ASC.Files/Server/Model/FileEntryWrapper.cs +++ b/products/ASC.Files/Server/Model/FileEntryWrapper.cs @@ -37,13 +37,8 @@ namespace ASC.Api.Documents /// /// [DataContract(Namespace = "")] - public abstract class FileEntryWrapper + public abstract class FileEntryWrapper { - /// - /// - [DataMember] - public T Id { get; set; } - /// /// [DataMember(IsRequired = true)] @@ -113,9 +108,8 @@ namespace ASC.Api.Documents /// /// /// - protected FileEntryWrapper(FileEntry entry, EmployeeWraperHelper employeeWraperHelper, ApiDateTimeHelper apiDateTimeHelper) + protected FileEntryWrapper(FileEntry entry, EmployeeWraperHelper employeeWraperHelper, ApiDateTimeHelper apiDateTimeHelper) { - Id = entry.ID; Title = entry.Title; Access = entry.Access; Shared = entry.Shared; @@ -138,6 +132,36 @@ namespace ASC.Api.Documents } } + /// + /// + [DataContract(Namespace = "")] + public abstract class FileEntryWrapper : FileEntryWrapper + { + /// + /// + [DataMember] + public T Id { get; set; } + + + /// + /// + /// + /// + protected FileEntryWrapper(FileEntry entry, EmployeeWraperHelper employeeWraperHelper, ApiDateTimeHelper apiDateTimeHelper) + : base(entry, employeeWraperHelper, apiDateTimeHelper) + { + Id = entry.ID; + } + + /// + /// + /// + protected FileEntryWrapper() + { + + } + } + public class FileEntryWrapperHelper { public ApiDateTimeHelper ApiDateTimeHelper { get; } diff --git a/products/ASC.Files/Server/Model/FolderContentWrapper.cs b/products/ASC.Files/Server/Model/FolderContentWrapper.cs index 2e4a934227..ec24b85d37 100644 --- a/products/ASC.Files/Server/Model/FolderContentWrapper.cs +++ b/products/ASC.Files/Server/Model/FolderContentWrapper.cs @@ -47,7 +47,7 @@ namespace ASC.Api.Documents /// /// [DataMember(IsRequired = false, EmitDefaultValue = false)] - public List> Folders { get; set; } + public List Folders { get; set; } /// /// @@ -92,7 +92,7 @@ namespace ASC.Api.Documents { Current = FolderWrapper.GetSample(), Files = new List>(new[] { FileWrapper.GetSample(), FileWrapper.GetSample() }), - Folders = new List>(new[] { FolderWrapper.GetSample(), FolderWrapper.GetSample() }), + Folders = new List(new[] { FolderWrapper.GetSample(), FolderWrapper.GetSample() }), PathParts = new { key = "Key", @@ -124,7 +124,23 @@ namespace ASC.Api.Documents var result = new FolderContentWrapper { Files = folderItems.Entries.OfType>().Select(FileWrapperHelper.Get).ToList(), - Folders = folderItems.Entries.OfType>().Select(FolderWrapperHelper.Get).ToList(), + Folders = folderItems.Entries + .Where(r => r.FileEntryType == FileEntryType.Folder) + .Select(r => + { + FileEntryWrapper wrapper = null; + if (r is Folder fol1) + { + wrapper = FolderWrapperHelper.Get(fol1); + } + if (r is Folder fol2) + { + wrapper = FolderWrapperHelper.Get(fol2); + } + + return wrapper; + } + ).ToList(), PathParts = folderItems.FolderPathParts, StartIndex = startIndex }; diff --git a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs index 74d8f02b3d..c17db31a12 100644 --- a/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs +++ b/products/ASC.Files/Server/Services/WCFService/Wrappers/DataWrapper.cs @@ -35,7 +35,7 @@ namespace ASC.Web.Files.Services.WCFService public class DataWrapper { [DataMember(IsRequired = false, Name = "entries", EmitDefaultValue = false)] - public ItemList> Entries { get; set; } + public ItemList Entries { get; set; } [DataMember(IsRequired = false, Name = "total")] public int Total { get; set; } diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index 997471d667..3c5853a591 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -242,14 +242,14 @@ namespace ASC.Web.Files.Utils cache = AscCache.Memory; } - public IEnumerable> GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) + public IEnumerable GetEntries(Folder parent, int from, int count, FilterType filter, bool subjectGroup, Guid subjectId, string searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy, out int total) { total = 0; if (parent == null) throw new ArgumentNullException("parent", FilesCommonResource.ErrorMassage_FolderNotFound); var fileSecurity = FileSecurity; - var entries = Enumerable.Empty>(); + var entries = Enumerable.Empty(); searchInContent = searchInContent && filter != FilterType.ByExtension && !Equals(parent.ID, GlobalFolderHelper.FolderTrash); @@ -390,33 +390,33 @@ namespace ASC.Web.Files.Utils if (orderBy.SortedBy != SortedByType.New) { - entries = SortEntries(entries, orderBy); + entries = SortEntries(entries, orderBy); total = entries.Count(); if (0 < from) entries = entries.Skip(from); if (0 < count) entries = entries.Take(count); } - entries = FileMarker.SetTagsNew(parent, entries); + entries = FileMarker.SetTagsNew(parent, entries); //sorting after marking if (orderBy.SortedBy == SortedByType.New) { - entries = SortEntries(entries, orderBy); + entries = SortEntries(entries, orderBy); total = entries.Count(); if (0 < from) entries = entries.Skip(from); if (0 < count) entries = entries.Take(count); } - SetFileStatus(entries.Where(r => r != null && r.ID != null && r.FileEntryType == FileEntryType.File).Select(r => r as File).ToList()); + SetFileStatus(entries.OfType>().Where(r => r != null && r.ID != null && r.FileEntryType == FileEntryType.File).Select(r => r as File).ToList()); return entries; } - public IEnumerable> GetThirpartyFolders(Folder parent, string searchText = null) + public IEnumerable> GetThirpartyFolders(Folder parent, string searchText = null) { - var folderList = new List>(); + var folderList = new List>(); if ((parent.ID.Equals(GlobalFolderHelper.FolderMy) || parent.ID.Equals(GlobalFolderHelper.FolderCommon)) && ThirdpartyConfiguration.SupportInclusion @@ -431,13 +431,13 @@ namespace ASC.Web.Files.Utils var providers = providerDao.GetProvidersInfo(parent.RootFolderType, searchText); folderList = providers - .Select(providerInfo => GetFakeThirdpartyFolder(providerInfo, parent.ID)) + .Select(providerInfo => GetFakeThirdpartyFolder(providerInfo, parent.ID.ToString())) .Where(r => fileSecurity.CanRead(r)).ToList(); if (folderList.Any()) { - var securityDao = DaoFactory.GetSecurityDao(); - securityDao.GetPureShareRecords(folderList.Cast>().ToArray()) + var securityDao = DaoFactory.GetSecurityDao(); + securityDao.GetPureShareRecords(folderList) //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) .Select(x => x.EntryId).Distinct().ToList() .ForEach(id => @@ -498,11 +498,11 @@ namespace ASC.Web.Files.Utils return entries; } - public IEnumerable> SortEntries(IEnumerable> entries, OrderBy orderBy) + public IEnumerable SortEntries(IEnumerable entries, OrderBy orderBy) { if (entries == null || !entries.Any()) return entries; - Comparison> sorter; + Comparison sorter; if (orderBy == null) { @@ -584,14 +584,14 @@ namespace ASC.Web.Files.Utils return result; } - public Folder GetFakeThirdpartyFolder(IProviderInfo providerInfo, object parentFolderId = null) + public Folder GetFakeThirdpartyFolder(IProviderInfo providerInfo, string parentFolderId = null) { //Fake folder. Don't send request to third party - var folder = ServiceProvider.GetService>(); + var folder = ServiceProvider.GetService>(); - folder.ParentFolderID = (T)parentFolderId; + folder.ParentFolderID = parentFolderId; - folder.ID = (T)providerInfo.RootFolderId; + folder.ID = providerInfo.RootFolderId; folder.CreateBy = providerInfo.Owner; folder.CreateOn = providerInfo.CreateOn; folder.FolderType = FolderType.DEFAULT; @@ -600,7 +600,7 @@ namespace ASC.Web.Files.Utils folder.ProviderId = providerInfo.ID; folder.ProviderKey = providerInfo.ProviderKey; folder.RootFolderCreator = providerInfo.Owner; - folder.RootFolderId = (T)Convert.ChangeType(providerInfo.RootFolderId, typeof(T)); + folder.RootFolderId = providerInfo.RootFolderId; folder.RootFolderType = providerInfo.RootFolderType; folder.Shareable = false; folder.Title = providerInfo.CustomerTitle; diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index df202df218..c8a53c75d1 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -500,7 +500,7 @@ namespace ASC.Web.Files.Utils return news; } - public List> MarkedItems(Folder folder) + public List MarkedItems(Folder folder) { if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound); if (!FileSecurity.CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder); @@ -513,7 +513,7 @@ namespace ASC.Web.Files.Utils var folderDao = DaoFactory.GetFolderDao(); var tags = (tagDao.GetNewTags(AuthContext.CurrentAccount.ID, folder, true) ?? new List()).ToList(); - if (!tags.Any()) return new List>(); + if (!tags.Any()) return new List(); if (Equals(folder.ID, GlobalFolder.GetFolderMy(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderCommon(this, DaoFactory)) || Equals(folder.ID, GlobalFolder.GetFolderShare(DaoFactory))) { @@ -562,7 +562,7 @@ namespace ASC.Web.Files.Utils entryTags[parentEntry].Count -= entryTag.Value.Count; } - var result = new List>(); + var result = new List(); foreach (var entryTag in entryTags) { @@ -580,7 +580,7 @@ namespace ASC.Web.Files.Utils return result; } - public IEnumerable> SetTagsNew(Folder parent, IEnumerable> entries) + public IEnumerable SetTagsNew(Folder parent, IEnumerable entries) { var tagDao = DaoFactory.GetTagDao(); var folderDao = DaoFactory.GetFolderDao(); @@ -670,7 +670,9 @@ namespace ASC.Web.Files.Utils } } - entries.ToList().ForEach( + entries.OfType>() + .ToList() + .ForEach( entry => { var curTag = totalTags.FirstOrDefault(tag => tag.EntryType == entry.FileEntryType && tag.EntryId.Equals(entry.ID)); From 314c2f9198ad80ce037fd363bb3966b8a95eb36d Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 10 Mar 2020 18:54:08 +0300 Subject: [PATCH 09/30] Files: added ProviderFileDao, ProviderFolderDao --- .../Server/Controllers/FilesController.cs | 2 +- .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 2 + .../Server/Core/Dao/TeamlabDao/TagDao.cs | 21 +- .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 11 +- .../Thirdparty/Dropbox/DropboxDaoSelector.cs | 53 +- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 16 +- .../Thirdparty/Dropbox/DropboxFolderDao.cs | 16 +- .../Thirdparty/Dropbox/DropboxSecurityDao.cs | 19 +- .../Core/Thirdparty/Dropbox/DropboxTagDao.cs | 29 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 329 ++++++------ .../Thirdparty/ProviderDao/ProviderFileDao.cs | 483 ++++++++++++++++++ .../ProviderDao/ProviderFolderDao.cs | 356 +++++++++++++ .../ProviderDao/ProviderSecutiryDao.cs | 15 +- .../Core/Thirdparty/RegexDaoSelectorBase.cs | 3 +- 14 files changed, 1141 insertions(+), 214 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 862e3033c9..ae2a18126a 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -232,7 +232,7 @@ namespace ASC.Api.Documents [Read("@common")] public FolderContentWrapper GetCommonFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.GetFolderCommon(), userIdOrGroupId, filterType); + return ToFolderContentWrapper(GlobalFolderHelper.FolderCommon, userIdOrGroupId, filterType); } /// diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index 6dac1acd38..6083fdf849 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -78,6 +78,8 @@ namespace ASC.Files.Core.Data .AddSecurityDaoService() .AddCachedProviderAccountDaoService() .AddProviderSecurityDaoService() + .AddProviderFileDaoService() + .AddProviderFolderDaoService() ; } } diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs index c31650bae4..ad1c6e21f4 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/TagDao.cs @@ -41,7 +41,7 @@ using ASC.Web.Studio.Utility; namespace ASC.Files.Core.Data { - internal class TagDao : AbstractDao, ITagDao + internal class TagDao : AbstractDao, ITagDao { private static readonly object syncRoot = new object(); @@ -73,7 +73,7 @@ namespace ASC.Files.Core.Data { } - public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) { var filesId = fileEntries.Where(e => e.FileEntryType == FileEntryType.File).Select(e => MappingID(e.ID).ToString()).ToList(); var foldersId = fileEntries.Where(e => e.FileEntryType == FileEntryType.Folder).Select(e => MappingID(e.ID).ToString()).ToList(); @@ -88,7 +88,7 @@ namespace ASC.Files.Core.Data return FromQuery(q); } - public IEnumerable GetTags(int entryID, FileEntryType entryType, TagType tagType) + public IEnumerable GetTags(T entryID, FileEntryType entryType, TagType tagType) { var q = Query(FilesDbContext.Tag) .Join(FilesDbContext.TagLink, r => r.Id, l => l.TagId, (tag, link) => new TagLinkData { Tag = tag, Link = link }) @@ -376,19 +376,19 @@ namespace ASC.Files.Core.Data } } - public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) { - return GetNewTags(subject, new List>(1) { fileEntry }); + return GetNewTags(subject, new List>(1) { fileEntry }); } - public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) { List result; var tags = fileEntries.Select(r => new DbFilesTagLink { TenantId = TenantID, - EntryId = MappingID((r as File)?.ID ?? (r as Folder)?.ID).ToString(), + EntryId = MappingID(r.ID).ToString(), EntryType = (r.FileEntryType == FileEntryType.File) ? FileEntryType.File : FileEntryType.Folder }) .ToList(); @@ -414,9 +414,9 @@ namespace ASC.Files.Core.Data return result; } - public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - if (parentFolder == null || parentFolder.ID == 0) + if (parentFolder == null || parentFolder.ID.Equals(default)) throw new ArgumentException("folderId"); var result = new List(); @@ -634,7 +634,8 @@ namespace ASC.Files.Core.Data { public static DIHelper AddTagDaoService(this DIHelper services) { - services.TryAddScoped, TagDao>(); + services.TryAddScoped, TagDao>(); + services.TryAddScoped>(); return services .AddUserManagerService() .AddFilesDbContextService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index 79180247ed..183e9aaa2b 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -49,7 +49,7 @@ namespace ASC.Files.Thirdparty.Dropbox { internal abstract class DropboxDaoBase { - protected readonly DropboxDaoSelector DropboxDaoSelector; + protected DropboxDaoSelector DropboxDaoSelector { get; set; } public int TenantID { get; private set; } public DropboxProviderInfo DropboxProviderInfo { get; private set; } @@ -76,7 +76,7 @@ namespace ASC.Files.Thirdparty.Dropbox FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); } - protected DropboxDaoBase(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + public void Init(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) { DropboxProviderInfo = dropboxInfo.DropboxProviderInfo; PathPrefix = dropboxInfo.PathPrefix; @@ -124,13 +124,6 @@ namespace ASC.Files.Thirdparty.Dropbox return set.Where(r => r.TenantId == TenantID); } - private static string GetTenantColumnName(string table) - { - const string tenant = "tenant_id"; - if (!table.Contains(" ")) return tenant; - return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant; - } - protected static string GetParentFolderPath(Metadata dropboxItem) { diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs index 94f637065f..0935e75536 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs @@ -28,14 +28,18 @@ using System; using System.Globalization; using System.Text.RegularExpressions; +using ASC.Common; using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxDaoSelector : RegexDaoSelectorBase { + public IServiceProvider ServiceProvider { get; } public TenantManager TenantManager { get; } public IDaoFactory DaoFactory { get; } @@ -47,31 +51,48 @@ namespace ASC.Files.Thirdparty.Dropbox public string PathPrefix { get; set; } } - public DropboxDaoSelector(TenantManager tenantManager, IDaoFactory daoFactory) + public DropboxDaoSelector(IServiceProvider serviceProvider, TenantManager tenantManager, IDaoFactory daoFactory) : base(new Regex(@"^dropbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) { + ServiceProvider = serviceProvider; TenantManager = tenantManager; DaoFactory = daoFactory; } public override IFileDao GetFileDao(string id) - { - return new DropboxFileDao(GetInfo(id), this); + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; } public override IFolderDao GetFolderDao(string id) - { - return new DropboxFolderDao(GetInfo(id), this); + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; } public override ITagDao GetTagDao(string id) - { - return new DropboxTagDao(GetInfo(id), this); + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; } public override ISecurityDao GetSecurityDao(string id) - { - return new DropboxSecurityDao(GetInfo(id), this); + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; } public override string ConvertId(string id) @@ -145,5 +166,19 @@ namespace ASC.Files.Thirdparty.Dropbox // dropboxProviderInfo.UpdateTitle(newTitle); //This will update cached version too //} } + } + + public static class DropboxDaoSelectorExtention + { + public static DIHelper AddDropboxDaoSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddDropboxSecurityDaoService() + .AddDropboxTagDaoService() + .AddDropboxFolderDaoService() + .AddDropboxFileDaoService(); + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs index d409f2d51a..2c936d3669 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using ASC.Common; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -54,11 +55,6 @@ namespace ASC.Files.Thirdparty.Dropbox SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) { - } - - public DropboxFileDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) - : base(dropboxInfo, dropboxDaoSelector) - { } public void InvalidateCache(string fileId) @@ -592,5 +588,15 @@ namespace ASC.Files.Thirdparty.Dropbox } #endregion + } + + public static class DropboxFileDaoExtention + { + public static DIHelper AddDropboxFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs index 84a248ed68..131e069b02 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using ASC.Common; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -48,11 +49,6 @@ namespace ASC.Files.Thirdparty.Dropbox SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) { - } - - public DropboxFolderDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) - : base(dropboxInfo, dropboxDaoSelector) - { } public Folder GetFolder(string folderId) @@ -411,5 +407,15 @@ namespace ASC.Files.Thirdparty.Dropbox } #endregion + } + + public static class DropboxFolderDaoExtention + { + public static DIHelper AddDropboxFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs index 788ecf616b..561be172a6 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using ASC.Common; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -39,7 +40,8 @@ namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxSecurityDao : DropboxDaoBase, ISecurityDao { - public DropboxSecurityDao(IServiceProvider serviceProvider, + public DropboxSecurityDao( + IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, @@ -47,11 +49,6 @@ namespace ASC.Files.Thirdparty.Dropbox SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) { - } - - public DropboxSecurityDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) - : base(dropboxInfo, dropboxDaoSelector) - { } public void SetShare(FileShareRecord r) @@ -95,5 +92,15 @@ namespace ASC.Files.Thirdparty.Dropbox { throw new NotImplementedException(); } + } + + public static class DropboxSecurityDaoExtention + { + public static DIHelper AddDropboxSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs index 2b63dc2237..e59ec99ced 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs @@ -29,20 +29,25 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxTagDao : DropboxDaoBase, ITagDao - { - public DropboxTagDao(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) - : base(dropboxInfo, dropboxDaoSelector) - { - } - + { + public DropboxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + #region ITagDao Members - + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) { return null; @@ -178,5 +183,15 @@ namespace ASC.Files.Thirdparty.Dropbox return obj.Id.GetHashCode() + obj.TenantId.GetHashCode(); } } + } + + public static class DropboxTagDaoExtention + { + public static DIHelper AddDropboxTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index c6b03cc0c9..280933f75e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -27,8 +27,15 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Data; +using ASC.Files.Resources; using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; using Microsoft.Extensions.DependencyInjection; @@ -38,9 +45,18 @@ namespace ASC.Files.Thirdparty.ProviderDao { private readonly List Selectors; - public ProviderDaoBase(IServiceProvider serviceProvider) + public ProviderDaoBase( + IServiceProvider serviceProvider, + SecurityDao securityDao, + TagDao tagDao, + SetupInfo setupInfo, + FileConverter fileConverter) { ServiceProvider = serviceProvider; + SecurityDao = securityDao; + TagDao = tagDao; + SetupInfo = setupInfo; + FileConverter = fileConverter; Selectors = new List { @@ -56,35 +72,36 @@ namespace ASC.Files.Thirdparty.ProviderDao } public IServiceProvider ServiceProvider { get; } + public SecurityDao SecurityDao { get; } + public TagDao TagDao { get; } + public SetupInfo SetupInfo { get; } + public FileConverter FileConverter { get; } - //protected bool IsCrossDao(object id1, object id2) - //{ - // if (id2 == null || id1 == null) - // return false; - // return !Equals(GetSelector(id1).GetIdCode(id1), GetSelector(id2).GetIdCode(id2)); - //} + protected bool IsCrossDao(string id1, string id2) + { + if (id2 == null || id1 == null) + return false; + return !Equals(GetSelector(id1).GetIdCode(id1), GetSelector(id2).GetIdCode(id2)); + } protected IDaoSelector GetSelector(string id) { return Selectors.FirstOrDefault(selector => selector.IsMatch(id)); } - //protected void SetSharedProperty(IEnumerable> entries) - //{ - // using (var securityDao = TryGetSecurityDao()) - // { - // securityDao.GetPureShareRecords(entries.ToArray()) - // //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) - // .Select(x => x.EntryId).Distinct().ToList() - // .ForEach(id => - // { - // var firstEntry = entries.FirstOrDefault(y => y.ID.Equals(id)); + protected void SetSharedProperty(IEnumerable> entries) + { + SecurityDao.GetPureShareRecords(entries.ToArray()) + //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) + .Select(x => x.EntryId).Distinct().ToList() + .ForEach(id => + { + var firstEntry = entries.FirstOrDefault(y => y.ID.Equals(id)); - // if (firstEntry != null) - // firstEntry.Shared = true; - // }); - // } - //} + if (firstEntry != null) + firstEntry.Shared = true; + }); + } protected IEnumerable GetSelectors() { @@ -92,160 +109,162 @@ namespace ASC.Files.Thirdparty.ProviderDao } - //protected File PerformCrossDaoFileCopy(object fromFileId, object toFolderId, bool deleteSourceFile) - //{ - // var fromSelector = GetSelector(fromFileId); - // var toSelector = GetSelector(toFolderId); - // //Get File from first dao - // var fromFileDao = fromSelector.GetFileDao(fromFileId); - // var toFileDao = toSelector.GetFileDao(toFolderId); - // var fromFile = fromFileDao.GetFile(fromSelector.ConvertId(fromFileId)); + protected File PerformCrossDaoFileCopy(string fromFileId, string toFolderId, bool deleteSourceFile) + { + var fromSelector = GetSelector(fromFileId); + var toSelector = GetSelector(toFolderId); + //Get File from first dao + var fromFileDao = fromSelector.GetFileDao(fromFileId); + var toFileDao = toSelector.GetFileDao(toFolderId); + var fromFile = fromFileDao.GetFile(fromSelector.ConvertId(fromFileId)); - // if (fromFile.ContentLength > SetupInfo.AvailableFileSize) - // { - // throw new Exception(string.Format(deleteSourceFile ? FilesCommonResource.ErrorMassage_FileSizeMove : FilesCommonResource.ErrorMassage_FileSizeCopy, - // FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); - // } + if (fromFile.ContentLength > SetupInfo.AvailableFileSize) + { + throw new Exception(string.Format(deleteSourceFile ? FilesCommonResource.ErrorMassage_FileSizeMove : FilesCommonResource.ErrorMassage_FileSizeCopy, + FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); + } - // using (var securityDao = TryGetSecurityDao()) - // using (var tagDao = TryGetTagDao()) - // { - // var fromFileShareRecords = securityDao.GetPureShareRecords(fromFile).Where(x => x.EntryType == FileEntryType.File); - // var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFile).ToList(); - // var fromFileLockTag = tagDao.GetTags(fromFile.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); + var securityDao = SecurityDao; + var tagDao = TagDao; - // var toFile = new File - // { - // Title = fromFile.Title, - // Encrypted = fromFile.Encrypted, - // FolderID = toSelector.ConvertId(toFolderId) - // }; + var fromFileShareRecords = securityDao.GetPureShareRecords(fromFile).Where(x => x.EntryType == FileEntryType.File); + var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFile).ToList(); + var fromFileLockTag = tagDao.GetTags(fromFile.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); - // fromFile.ID = fromSelector.ConvertId(fromFile.ID); + var toFile = ServiceProvider.GetService>(); - // var mustConvert = !string.IsNullOrEmpty(fromFile.ConvertedType); - // using (var fromFileStream = mustConvert - // ? FileConverter.Exec(fromFile) - // : fromFileDao.GetFileStream(fromFile)) - // { - // toFile.ContentLength = fromFileStream.CanSeek ? fromFileStream.Length : fromFile.ContentLength; - // toFile = toFileDao.SaveFile(toFile, fromFileStream); - // } + toFile.Title = fromFile.Title; + toFile.Encrypted = fromFile.Encrypted; + toFile.FolderID = toSelector.ConvertId(toFolderId); - // if (deleteSourceFile) - // { - // if (fromFileShareRecords.Any()) - // fromFileShareRecords.ToList().ForEach(x => - // { - // x.EntryId = toFile.ID; - // securityDao.SetShare(x); - // }); + fromFile.ID = fromSelector.ConvertId(fromFile.ID); - // var fromFileTags = fromFileNewTags; - // if (fromFileLockTag != null) fromFileTags.Add(fromFileLockTag); + var mustConvert = !string.IsNullOrEmpty(fromFile.ConvertedType); + using (var fromFileStream = mustConvert + ? FileConverter.Exec(fromFile) + : fromFileDao.GetFileStream(fromFile)) + { + toFile.ContentLength = fromFileStream.CanSeek ? fromFileStream.Length : fromFile.ContentLength; + toFile = toFileDao.SaveFile(toFile, fromFileStream); + } - // if (fromFileTags.Any()) - // { - // fromFileTags.ForEach(x => x.EntryId = toFile.ID); + if (deleteSourceFile) + { + if (fromFileShareRecords.Any()) + fromFileShareRecords.ToList().ForEach(x => + { + x.EntryId = toFile.ID; + securityDao.SetShare(x); + }); - // tagDao.SaveTags(fromFileTags); - // } + var fromFileTags = fromFileNewTags; + if (fromFileLockTag != null) fromFileTags.Add(fromFileLockTag); - // //Delete source file if needed - // fromFileDao.DeleteFile(fromSelector.ConvertId(fromFileId)); - // } - // return toFile; - // } - //} + if (fromFileTags.Any()) + { + fromFileTags.ForEach(x => x.EntryId = toFile.ID); - //protected Folder PerformCrossDaoFolderCopy(object fromFolderId, object toRootFolderId, bool deleteSourceFolder, CancellationToken? cancellationToken) - //{ - // //Things get more complicated - // var fromSelector = GetSelector(fromFolderId); - // var toSelector = GetSelector(toRootFolderId); + tagDao.SaveTags(fromFileTags); + } - // var fromFolderDao = fromSelector.GetFolderDao(fromFolderId); - // var fromFileDao = fromSelector.GetFileDao(fromFolderId); - // //Create new folder in 'to' folder - // var toFolderDao = toSelector.GetFolderDao(toRootFolderId); - // //Ohh - // var fromFolder = fromFolderDao.GetFolder(fromSelector.ConvertId(fromFolderId)); + //Delete source file if needed + fromFileDao.DeleteFile(fromSelector.ConvertId(fromFileId)); + } + return toFile; + } - // var toFolder = toFolderDao.GetFolder(fromFolder.Title, toSelector.ConvertId(toRootFolderId)); - // var toFolderId = toFolder != null - // ? toFolder.ID - // : toFolderDao.SaveFolder( - // new Folder - // { - // Title = fromFolder.Title, - // ParentFolderID = toSelector.ConvertId(toRootFolderId) - // }); + protected Folder PerformCrossDaoFolderCopy(string fromFolderId, string toRootFolderId, bool deleteSourceFolder, CancellationToken? cancellationToken) + { + //Things get more complicated + var fromSelector = GetSelector(fromFolderId); + var toSelector = GetSelector(toRootFolderId); - // var foldersToCopy = fromFolderDao.GetFolders(fromSelector.ConvertId(fromFolderId)); - // var fileIdsToCopy = fromFileDao.GetFiles(fromSelector.ConvertId(fromFolderId)); - // Exception copyException = null; - // //Copy files first - // foreach (var fileId in fileIdsToCopy) - // { - // if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); - // try - // { - // PerformCrossDaoFileCopy(fileId, toFolderId, deleteSourceFolder); - // } - // catch (Exception ex) - // { - // copyException = ex; - // } - // } - // foreach (var folder in foldersToCopy) - // { - // if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); - // try - // { - // PerformCrossDaoFolderCopy(folder.ID, toFolderId, deleteSourceFolder, cancellationToken); - // } - // catch (Exception ex) - // { - // copyException = ex; - // } - // } + var fromFolderDao = fromSelector.GetFolderDao(fromFolderId); + var fromFileDao = fromSelector.GetFileDao(fromFolderId); + //Create new folder in 'to' folder + var toFolderDao = toSelector.GetFolderDao(toRootFolderId); + //Ohh + var fromFolder = fromFolderDao.GetFolder(fromSelector.ConvertId(fromFolderId)); - // if (deleteSourceFolder) - // { - // using (var securityDao = TryGetSecurityDao()) - // { - // var fromFileShareRecords = securityDao.GetPureShareRecords(fromFolder) - // .Where(x => x.EntryType == FileEntryType.Folder); + var toFolder1 = ServiceProvider.GetService>(); + toFolder1.Title = fromFolder.Title; + toFolder1.ParentFolderID = toSelector.ConvertId(toRootFolderId); - // if (fromFileShareRecords.Any()) - // { - // fromFileShareRecords.ToList().ForEach(x => - // { - // x.EntryId = toFolderId; - // securityDao.SetShare(x); - // }); - // } - // } + var toFolder = toFolderDao.GetFolder(fromFolder.Title, toSelector.ConvertId(toRootFolderId)); + var toFolderId = toFolder != null + ? toFolder.ID + : toFolderDao.SaveFolder(toFolder1); - // using (var tagDao = TryGetTagDao()) - // { - // var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFolder).ToList(); + var foldersToCopy = fromFolderDao.GetFolders(fromSelector.ConvertId(fromFolderId)); + var fileIdsToCopy = fromFileDao.GetFiles(fromSelector.ConvertId(fromFolderId)); + Exception copyException = null; + //Copy files first + foreach (var fileId in fileIdsToCopy) + { + if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + try + { + PerformCrossDaoFileCopy(fileId, toFolderId, deleteSourceFolder); + } + catch (Exception ex) + { + copyException = ex; + } + } + foreach (var folder in foldersToCopy) + { + if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + try + { + PerformCrossDaoFolderCopy(folder.ID, toFolderId, deleteSourceFolder, cancellationToken); + } + catch (Exception ex) + { + copyException = ex; + } + } - // if (fromFileNewTags.Any()) - // { - // fromFileNewTags.ForEach(x => x.EntryId = toFolderId); + if (deleteSourceFolder) + { + var securityDao = SecurityDao; + var fromFileShareRecords = securityDao.GetPureShareRecords(fromFolder) + .Where(x => x.EntryType == FileEntryType.Folder); - // tagDao.SaveTags(fromFileNewTags); - // } - // } + if (fromFileShareRecords.Any()) + { + fromFileShareRecords.ToList().ForEach(x => + { + x.EntryId = toFolderId; + securityDao.SetShare(x); + }); + } - // if (copyException == null) - // fromFolderDao.DeleteFolder(fromSelector.ConvertId(fromFolderId)); - // } + var tagDao = TagDao; + var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFolder).ToList(); - // if (copyException != null) throw copyException; + if (fromFileNewTags.Any()) + { + fromFileNewTags.ForEach(x => x.EntryId = toFolderId); - // return toFolderDao.GetFolder(toSelector.ConvertId(toFolderId)); - //} + tagDao.SaveTags(fromFileNewTags); + } + + if (copyException == null) + fromFolderDao.DeleteFolder(fromSelector.ConvertId(fromFolderId)); + } + + if (copyException != null) throw copyException; + + return toFolderDao.GetFolder(toSelector.ConvertId(toFolderId)); + } + } + + public static class ProviderDaoBaseExtention + { + public static DIHelper AddProviderDaoBaseService(this DIHelper services) + { + return services + .AddDropboxDaoSelectorService(); + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs new file mode 100644 index 0000000000..41885ec135 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -0,0 +1,483 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Data; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.ProviderDao +{ + internal class ProviderFileDao : ProviderDaoBase, IFileDao + { + public ProviderFileDao(IServiceProvider serviceProvider, + SecurityDao securityDao, + TagDao tagDao, + SetupInfo setupInfo, + FileConverter fileConverter) + : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + { + + } + + public void InvalidateCache(string fileId) + { + var selector = GetSelector(fileId); + var fileDao = selector.GetFileDao(fileId); + fileDao.InvalidateCache(selector.ConvertId(fileId)); + } + + public File GetFile(string fileId) + { + var selector = GetSelector(fileId); + + var fileDao = selector.GetFileDao(fileId); + var result = fileDao.GetFile(selector.ConvertId(fileId)); + + if (result != null) + { + SetSharedProperty(new[] { result }); + } + + return result; + } + + public File GetFile(string fileId, int fileVersion) + { + var selector = GetSelector(fileId); + + var fileDao = selector.GetFileDao(fileId); + var result = fileDao.GetFile(selector.ConvertId(fileId), fileVersion); + + if (result != null) + { + SetSharedProperty(new[] { result }); + } + + return result; + } + + public File GetFile(string parentId, string title) + { + var selector = GetSelector(parentId); + var fileDao = selector.GetFileDao(parentId); + var result = fileDao.GetFile(selector.ConvertId(parentId), title); + + if (result != null) + { + SetSharedProperty(new[] { result }); + } + + return result; + } + + public File GetFileStable(string fileId, int fileVersion = -1) + { + var selector = GetSelector(fileId); + + var fileDao = selector.GetFileDao(fileId); + var result = fileDao.GetFileStable(selector.ConvertId(fileId), fileVersion); + + if (result != null) + { + SetSharedProperty(new[] { result }); + } + + return result; + } + + public List> GetFileHistory(string fileId) + { + var selector = GetSelector(fileId); + var fileDao = selector.GetFileDao(fileId); + return fileDao.GetFileHistory(selector.ConvertId(fileId)); + } + + public List> GetFiles(string[] fileIds) + { + var result = Enumerable.Empty>(); + + foreach (var selector in GetSelectors()) + { + var selectorLocal = selector; + var matchedIds = fileIds.Where(selectorLocal.IsMatch); + + if (!matchedIds.Any()) continue; + + result = result.Concat(matchedIds.GroupBy(selectorLocal.GetIdCode) + .SelectMany(matchedId => + { + var fileDao = selectorLocal.GetFileDao(matchedId.FirstOrDefault()); + return fileDao.GetFiles(matchedId.Select(selectorLocal.ConvertId).ToArray()); + } + ) + .Where(r => r != null)); + } + + return result.ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + var result = Enumerable.Empty>(); + + foreach (var selector in GetSelectors()) + { + var selectorLocal = selector; + var matchedIds = fileIds.Where(selectorLocal.IsMatch); + + if (!matchedIds.Any()) continue; + + result = result.Concat(matchedIds.GroupBy(selectorLocal.GetIdCode) + .SelectMany(matchedId => + { + var fileDao = selectorLocal.GetFileDao(matchedId.FirstOrDefault()); + return fileDao.GetFilesForShare(matchedId.Select(selectorLocal.ConvertId).ToArray(), + filterType, subjectGroup, subjectID, searchText, searchInContent); + }) + .Where(r => r != null)); + } + + return result.ToList(); + } + + public List GetFiles(string parentId) + { + var selector = GetSelector(parentId); + var fileDao = selector.GetFileDao(parentId); + return fileDao.GetFiles(selector.ConvertId(parentId)).Where(r => r != null).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + var selector = GetSelector(parentId); + + var fileDao = selector.GetFileDao(parentId); + var result = fileDao + .GetFiles(selector.ConvertId(parentId), orderBy, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders) + .Where(r => r != null).ToList(); + + if (!result.Any()) return new List>(); + + SetSharedProperty(result); + + return result; + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + /// + /// Get stream of file + /// + /// + /// + /// Stream + public Stream GetFileStream(File file, long offset) + { + if (file == null) throw new ArgumentNullException("file"); + var fileId = file.ID; + var selector = GetSelector(fileId); + file.ID = selector.ConvertId(fileId); + + var fileDao = selector.GetFileDao(fileId); + var stream = fileDao.GetFileStream(file, offset); + file.ID = fileId; //Restore id + return stream; + } + + public bool IsSupportedPreSignedUri(File file) + { + if (file == null) throw new ArgumentNullException("file"); + var fileId = file.ID; + var selector = GetSelector(fileId); + file.ID = selector.ConvertId(fileId); + + var fileDao = selector.GetFileDao(fileId); + var isSupported = fileDao.IsSupportedPreSignedUri(file); + file.ID = fileId; //Restore id + return isSupported; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + if (file == null) throw new ArgumentNullException("file"); + var fileId = file.ID; + var selector = GetSelector(fileId); + file.ID = selector.ConvertId(fileId); + + var fileDao = selector.GetFileDao(fileId); + var streamUri = fileDao.GetPreSignedUri(file, expires); + file.ID = fileId; //Restore id + return streamUri; + } + + public File SaveFile(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + + var fileId = file.ID; + var folderId = file.FolderID; + + IDaoSelector selector; + File fileSaved = null; + //Convert + if (fileId != null) + { + selector = GetSelector(fileId); + file.ID = selector.ConvertId(fileId); + if (folderId != null) + file.FolderID = selector.ConvertId(folderId); + var fileDao = selector.GetFileDao(fileId); + fileSaved = fileDao.SaveFile(file, fileStream); + } + else if (folderId != null) + { + selector = GetSelector(folderId); + file.FolderID = selector.ConvertId(folderId); + var fileDao = selector.GetFileDao(folderId); + fileSaved = fileDao.SaveFile(file, fileStream); + } + + if (fileSaved != null) + { + return fileSaved; + } + throw new ArgumentException("No file id or folder id toFolderId determine provider"); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + if (file.ID == null) throw new ArgumentException("No file id or folder id toFolderId determine provider"); + + var fileId = file.ID; + var folderId = file.FolderID; + + //Convert + var selector = GetSelector(fileId); + + file.ID = selector.ConvertId(fileId); + if (folderId != null) file.FolderID = selector.ConvertId(folderId); + + var fileDao = selector.GetFileDao(fileId); + return fileDao.ReplaceFileVersion(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var selector = GetSelector(fileId); + var fileDao = selector.GetFileDao(fileId); + fileDao.DeleteFile(selector.ConvertId(fileId)); + } + + public bool IsExist(string title, object folderId) + { + var selector = GetSelector(folderId.ToString()); + + var fileDao = selector.GetFileDao(folderId.ToString()); + return fileDao.IsExist(title, selector.ConvertId(folderId.ToString())); + } + + public string MoveFile(string fileId, string toFolderId) + { + var selector = GetSelector(fileId); + if (IsCrossDao(fileId, toFolderId)) + { + var movedFile = PerformCrossDaoFileCopy(fileId, toFolderId, true); + return movedFile.ID; + } + + var fileDao = selector.GetFileDao(fileId); + return fileDao.MoveFile(selector.ConvertId(fileId), selector.ConvertId(toFolderId)); + } + + public File CopyFile(string fileId, string toFolderId) + { + var selector = GetSelector(fileId); + if (IsCrossDao(fileId, toFolderId)) + { + return PerformCrossDaoFileCopy(fileId, toFolderId, false); + } + + var fileDao = selector.GetFileDao(fileId); + return fileDao.CopyFile(selector.ConvertId(fileId), selector.ConvertId(toFolderId)); + } + + public string FileRename(File file, string newTitle) + { + var selector = GetSelector(file.ID); + var fileDao = selector.GetFileDao(file.ID); + return fileDao.FileRename(ConvertId(file), newTitle); + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + var selector = GetSelector(fileId); + + var fileDao = selector.GetFileDao(fileId); + return fileDao.UpdateComment(selector.ConvertId(fileId), fileVersion, comment); + } + + public void CompleteVersion(string fileId, int fileVersion) + { + var selector = GetSelector(fileId); + + var fileDao = selector.GetFileDao(fileId); + fileDao.CompleteVersion(selector.ConvertId(fileId), fileVersion); + } + + public void ContinueVersion(string fileId, int fileVersion) + { + var selector = GetSelector(fileId); + var fileDao = selector.GetFileDao(fileId); + fileDao.ContinueVersion(selector.ConvertId(fileId), fileVersion); + } + + public bool UseTrashForRemove(File file) + { + var selector = GetSelector(file.ID); + var fileDao = selector.GetFileDao(file.ID); + return fileDao.UseTrashForRemove(file); + } + + #region chunking + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + var fileDao = GetFileDao(file); + return fileDao.CreateUploadSession(ConvertId(file), contentLength); + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength) + { + var fileDao = GetFileDao(uploadSession.File); + uploadSession.File = ConvertId(uploadSession.File); + fileDao.UploadChunk(uploadSession, chunkStream, chunkLength); + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + var fileDao = GetFileDao(uploadSession.File); + uploadSession.File = ConvertId(uploadSession.File); + fileDao.AbortUploadSession(uploadSession); + } + + private IFileDao GetFileDao(File file) + { + if (file.ID != null) + return GetSelector(file.ID).GetFileDao(file.ID); + + if (file.FolderID != null) + return GetSelector(file.FolderID).GetFileDao(file.FolderID); + + throw new ArgumentException("Can't create instance of dao for given file.", "file"); + } + + private string ConvertId(string id) + { + return id != null ? GetSelector(id).ConvertId(id) : null; + } + + private File ConvertId(File file) + { + file.ID = ConvertId(file.ID); + file.FolderID = ConvertId(file.FolderID); + return file; + } + + #endregion + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + throw new NotImplementedException(); + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + throw new NotImplementedException(); + } + + public IEnumerable> Search(string text, bool bunch) + { + throw new NotImplementedException(); + } + + public bool IsExistOnStorage(File file) + { + throw new NotImplementedException(); + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + throw new NotImplementedException(); + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public Stream GetDifferenceStream(File file) + { + throw new NotImplementedException(); + } + + public bool ContainChanges(string fileId, int fileVersion) + { + throw new NotImplementedException(); + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class ProviderFileDaoExtention + { + public static DIHelper AddProviderFileDaoService(this DIHelper services) + { + services.TryAddScoped, ProviderFileDao>(); + + return services + .AddProviderDaoBaseService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs new file mode 100644 index 0000000000..955c1a5467 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs @@ -0,0 +1,356 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Data; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.ProviderDao +{ + internal class ProviderFolderDao : ProviderDaoBase, IFolderDao + { + public ProviderFolderDao( + IServiceProvider serviceProvider, + SecurityDao securityDao, + TagDao tagDao, + SetupInfo setupInfo, + FileConverter fileConverter) + : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + { + } + + public Folder GetFolder(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + var result = folderDao.GetFolder(selector.ConvertId(folderId)); + + if (result != null) + { + SetSharedProperty(new[] { result }); + } + + return result; + } + + public Folder GetFolder(string title, string parentId) + { + var selector = GetSelector(parentId); + return selector.GetFolderDao(parentId).GetFolder(title, selector.ConvertId(parentId)); + } + + public Folder GetRootFolder(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + return folderDao.GetRootFolder(selector.ConvertId(folderId)); + } + + public Folder GetRootFolderByFile(string fileId) + { + var selector = GetSelector(fileId); + var folderDao = selector.GetFolderDao(fileId); + return folderDao.GetRootFolderByFile(selector.ConvertId(fileId)); + } + + public List> GetFolders(string parentId) + { + var selector = GetSelector(parentId); + var folderDao = selector.GetFolderDao(parentId); + return folderDao + .GetFolders(selector.ConvertId(parentId)) + .Where(r => r != null) + .ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + var selector = GetSelector(parentId); + var folderDao = selector.GetFolderDao(parentId); + var result = folderDao.GetFolders(selector.ConvertId(parentId), orderBy, filterType, subjectGroup, subjectID, searchText, withSubfolders) +.Where(r => r != null).ToList(); + + if (!result.Any()) return new List>(); + + SetSharedProperty(result); + + return result; + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + var result = Enumerable.Empty>(); + + foreach (var selector in GetSelectors()) + { + var selectorLocal = selector; + var matchedIds = folderIds.Where(selectorLocal.IsMatch).ToList(); + + if (!matchedIds.Any()) continue; + + result = result.Concat(matchedIds.GroupBy(selectorLocal.GetIdCode) + .SelectMany(matchedId => + { + var folderDao = selectorLocal.GetFolderDao(matchedId.FirstOrDefault()); + return folderDao +.GetFolders(matchedId.Select(selectorLocal.ConvertId).ToArray(), +filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); + }) + .Where(r => r != null)); + } + + return result.Distinct().ToList(); + } + + public List> GetParentFolders(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + return folderDao.GetParentFolders(selector.ConvertId(folderId)); + } + + public string SaveFolder(Folder folder) + { + if (folder == null) throw new ArgumentNullException("folder"); + + if (folder.ID != null) + { + var folderId = folder.ID; + var selector = GetSelector(folderId); + folder.ID = selector.ConvertId(folderId); + var folderDao = selector.GetFolderDao(folderId); + var newFolderId = folderDao.SaveFolder(folder); + folder.ID = folderId; + return newFolderId; + } + if (folder.ParentFolderID != null) + { + var folderId = folder.ParentFolderID; + var selector = GetSelector(folderId); + folder.ParentFolderID = selector.ConvertId(folderId); + var folderDao = selector.GetFolderDao(folderId); + var newFolderId = folderDao.SaveFolder(folder); + folder.ParentFolderID = folderId; + return newFolderId; + + } + throw new ArgumentException("No folder id or parent folder id to determine provider"); + } + + public void DeleteFolder(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + folderDao.DeleteFolder(selector.ConvertId(folderId)); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var selector = GetSelector(folderId); + if (IsCrossDao(folderId, toFolderId)) + { + var newFolder = PerformCrossDaoFolderCopy(folderId, toFolderId, true, cancellationToken); + return newFolder?.ID; + } + var folderDao = selector.GetFolderDao(folderId); + return folderDao.MoveFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null); + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + return IsCrossDao(folderId, toFolderId) + ? PerformCrossDaoFolderCopy(folderId, toFolderId, false, cancellationToken) + : folderDao.CopyFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + if (!folderIds.Any()) return new Dictionary(); + + var selector = GetSelector(to); + var matchedIds = folderIds.Where(selector.IsMatch).ToArray(); + + if (!matchedIds.Any()) return new Dictionary(); + + var folderDao = selector.GetFolderDao(matchedIds.FirstOrDefault()); + return folderDao.CanMoveOrCopy(matchedIds, to); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var folderId = folder.ID; + var selector = GetSelector(folderId); + folder.ID = selector.ConvertId(folderId); + folder.ParentFolderID = selector.ConvertId(folder.ParentFolderID); + var folderDao = selector.GetFolderDao(folderId); + return folderDao.RenameFolder(folder, newTitle); + } + + public int GetItemsCount(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + return folderDao.GetItemsCount(selector.ConvertId(folderId)); + } + + public bool IsEmpty(string folderId) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + return folderDao.IsEmpty(selector.ConvertId(folderId)); + } + + public bool UseTrashForRemove(Folder folder) + { + var selector = GetSelector(folder.ID); + var folderDao = selector.GetFolderDao(folder.ID); + return folderDao.UseTrashForRemove(folder); + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + var selector = GetSelector(folderId); + bool useRecursive; + + var folderDao = selector.GetFolderDao(folderId); + useRecursive = folderDao.UseRecursiveOperation(folderId, null); + + if (toRootFolderId != null) + { + var toFolderSelector = GetSelector(toRootFolderId); + + var folderDao1 = toFolderSelector.GetFolderDao(toRootFolderId); + useRecursive = useRecursive && folderDao1.UseRecursiveOperation(folderId, toFolderSelector.ConvertId(toRootFolderId)); + } + return useRecursive; + } + + public bool CanCalculateSubitems(string entryId) + { + var selector = GetSelector(entryId); + var folderDao = selector.GetFolderDao(entryId); + return folderDao.CanCalculateSubitems(entryId); + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var selector = GetSelector(folderId); + var folderDao = selector.GetFolderDao(folderId); + var storageMaxUploadSize = folderDao.GetMaxUploadSize(selector.ConvertId(folderId), chunkedUpload); + + if (storageMaxUploadSize == -1 || storageMaxUploadSize == long.MaxValue) + { + storageMaxUploadSize = 1024L * 1024L * 1024L; + } + + return storageMaxUploadSize; + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + throw new NotImplementedException(); + } + + public IEnumerable> Search(string text, bool bunch) + { + throw new NotImplementedException(); + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public string GetFolderIDPhotos(bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public string GetBunchObjectID(string folderID) + { + throw new NotImplementedException(); + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + throw new NotImplementedException(); + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId = null) + { + throw new NotImplementedException(); + } + + public string GetFolderIDShare(bool createIfNotExists) + { + throw new NotImplementedException(); + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId = null) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class ProviderFolderDaoExtention + { + public static DIHelper AddProviderFolderDaoService(this DIHelper services) + { + services.TryAddScoped, ProviderFolderDao>(); + + return services + .AddProviderDaoBaseService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs index a39e3a2adf..b060d3cb18 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs @@ -32,6 +32,8 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Security; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; using Microsoft.Extensions.DependencyInjection; @@ -39,11 +41,13 @@ namespace ASC.Files.Thirdparty.ProviderDao { internal class ProviderSecurityDao : ProviderDaoBase, ISecurityDao { - public SecurityDao SecurityDao { get; } - - public ProviderSecurityDao(IServiceProvider serviceProvider, SecurityDao securityDao) : base(serviceProvider) + public ProviderSecurityDao(IServiceProvider serviceProvider, + SecurityDao securityDao, + TagDao tagDao, + SetupInfo setupInfo, + FileConverter fileConverter) + : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) { - SecurityDao = securityDao; } public void SetShare(FileShareRecord r) @@ -198,7 +202,8 @@ namespace ASC.Files.Thirdparty.ProviderDao { services.TryAddScoped, ProviderSecurityDao>(); - return services; + return services + .AddProviderDaoBaseService(); } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs index 728277a6ab..ee10e89cb7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -25,7 +25,6 @@ using System; -using System.Globalization; using System.Text.RegularExpressions; using ASC.Files.Core; @@ -100,7 +99,7 @@ namespace ASC.Files.Thirdparty public virtual bool IsMatch(string id) { - return id != null && Selector.IsMatch(Convert.ToString(id, CultureInfo.InvariantCulture)); + return id != null && Selector.IsMatch(id); } From 10931faf92d9d53adece0fc0c6524e715d1bed9c Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 11 Mar 2020 18:39:48 +0300 Subject: [PATCH 10/30] Files: box --- products/ASC.Files/Server/ASC.Files.csproj | 3 + .../Server/Core/Thirdparty/Box/BoxDaoBase.cs | 429 ++++++++++++++ .../Core/Thirdparty/Box/BoxDaoSelector.cs | 176 ++++++ .../Server/Core/Thirdparty/Box/BoxFileDao.cs | 556 ++++++++++++++++++ .../Core/Thirdparty/Box/BoxFolderDao.cs | 417 +++++++++++++ .../Core/Thirdparty/Box/BoxProviderInfo.cs | 325 ++++++++++ .../Core/Thirdparty/Box/BoxSecurityDao.cs | 99 ++++ .../Server/Core/Thirdparty/Box/BoxStorage.cs | 266 +++++++++ .../Server/Core/Thirdparty/Box/BoxTagDao.cs | 176 ++++++ .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 4 +- .../Thirdparty/Dropbox/DropboxDaoSelector.cs | 14 +- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 15 +- .../Core/Thirdparty/Dropbox/DropboxTagDao.cs | 31 +- .../Core/Thirdparty/ProviderAccountDao.cs | 25 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 6 +- .../ASC.Files/Server/proto/BoxCacheItem.proto | 10 + 16 files changed, 2502 insertions(+), 50 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxStorage.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs create mode 100644 products/ASC.Files/Server/proto/BoxCacheItem.proto diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index fb93e9b7c0..42ccd75603 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -19,10 +19,12 @@ true + + @@ -44,6 +46,7 @@ + diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs new file mode 100644 index 0000000000..72f5a87a15 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs @@ -0,0 +1,429 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Security.Cryptography; +using ASC.Web.Files.Classes; +using ASC.Web.Studio.Core; + +using Box.V2.Models; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.Box +{ + internal abstract class BoxDaoBase + { + public BoxDaoSelector BoxDaoSelector { get; set; } + + public int TenantID { get; private set; } + public BoxProviderInfo BoxProviderInfo { get; set; } + public string PathPrefix { get; private set; } + public FilesDbContext FilesDbContext { get; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantUtil TenantUtil { get; } + public SetupInfo SetupInfo { get; } + + public BoxDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + { + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + SetupInfo = setupInfo; + } + + public void Init(BoxDaoSelector.BoxInfo boxInfo, BoxDaoSelector boxDaoSelector) + { + BoxProviderInfo = boxInfo.BoxProviderInfo; + PathPrefix = boxInfo.PathPrefix; + BoxDaoSelector = boxDaoSelector; + } + + public void Dispose() + { + BoxProviderInfo.Dispose(); + } + + protected string MappingID(string id, bool saveIfNotExist = false) + { + if (id == null) return null; + + string result; + if (id.StartsWith("box")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + return result; + } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + + protected static string MakeBoxId(object entryId) + { + var id = Convert.ToString(entryId, CultureInfo.InvariantCulture); + return string.IsNullOrEmpty(id) + ? "0" + : id.TrimStart('/'); + } + + protected static string GetParentFolderId(BoxItem boxItem) + { + return boxItem == null || boxItem.Parent == null + ? null + : boxItem.Parent.Id; + } + + protected string MakeId(BoxItem boxItem) + { + var path = string.Empty; + if (boxItem != null) + { + path = boxItem.Id; + } + + return MakeId(path); + } + + protected string MakeId(string path = null) + { + return string.Format("{0}{1}", PathPrefix, + string.IsNullOrEmpty(path) || path == "0" + ? "" : ("-|" + path.TrimStart('/'))); + } + + protected string MakeFolderTitle(BoxFolder boxFolder) + { + if (boxFolder == null || IsRoot(boxFolder)) + { + return BoxProviderInfo.CustomerTitle; + } + + return Global.ReplaceInvalidCharsAndTruncate(boxFolder.Name); + } + + protected string MakeFileTitle(BoxFile boxFile) + { + if (boxFile == null || string.IsNullOrEmpty(boxFile.Name)) + { + return BoxProviderInfo.ProviderKey; + } + + return Global.ReplaceInvalidCharsAndTruncate(boxFile.Name); + } + + protected Folder ToFolder(BoxFolder boxFolder) + { + if (boxFolder == null) return null; + if (boxFolder is ErrorFolder) + { + //Return error entry + return ToErrorFolder(boxFolder as ErrorFolder); + } + + var isRoot = IsRoot(boxFolder); + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(boxFolder.Id); + folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(boxFolder)); + folder.CreateBy = BoxProviderInfo.Owner; + folder.CreateOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.CreatedAt ?? default); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = BoxProviderInfo.Owner; + folder.ModifiedOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.ModifiedAt ?? default); + folder.ProviderId = BoxProviderInfo.ID; + folder.ProviderKey = BoxProviderInfo.ProviderKey; + folder.RootFolderCreator = BoxProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = BoxProviderInfo.RootFolderType; + + folder.Shareable = false; + folder.Title = MakeFolderTitle(boxFolder); + folder.TotalFiles = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFile) : 0; + folder.TotalSubFolders = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFolder) : 0; + + if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) + folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); + + if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc) + folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn); + + return folder; + } + + protected static bool IsRoot(BoxFolder boxFolder) + { + return boxFolder.Id == "0"; + } + + private File ToErrorFile(ErrorFile boxFile) + { + if (boxFile == null) return null; + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(boxFile.ErrorId); + file.CreateBy = BoxProviderInfo.Owner; + file.CreateOn = TenantUtil.DateTimeNow(); + file.ModifiedBy = BoxProviderInfo.Owner; + file.ModifiedOn = TenantUtil.DateTimeNow(); + file.ProviderId = BoxProviderInfo.ID; + file.ProviderKey = BoxProviderInfo.ProviderKey; + file.RootFolderCreator = BoxProviderInfo.Owner; + file.RootFolderId = MakeId(); + file.RootFolderType = BoxProviderInfo.RootFolderType; + file.Title = MakeFileTitle(boxFile); + file.Error = boxFile.Error; + + return file; + } + + private Folder ToErrorFolder(ErrorFolder boxFolder) + { + if (boxFolder == null) return null; + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(boxFolder.ErrorId); + folder.ParentFolderID = null; + folder.CreateBy = BoxProviderInfo.Owner; + folder.CreateOn = TenantUtil.DateTimeNow(); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = BoxProviderInfo.Owner; + folder.ModifiedOn = TenantUtil.DateTimeNow(); + folder.ProviderId = BoxProviderInfo.ID; + folder.ProviderKey = BoxProviderInfo.ProviderKey; + folder.RootFolderCreator = BoxProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = BoxProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeFolderTitle(boxFolder); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + folder.Error = boxFolder.Error; + + return folder; + } + + public File ToFile(BoxFile boxFile) + { + if (boxFile == null) return null; + + if (boxFile is ErrorFile) + { + //Return error entry + return ToErrorFile(boxFile as ErrorFile); + } + + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(boxFile.Id); + file.Access = FileShare.None; + file.ContentLength = boxFile.Size.HasValue ? (long)boxFile.Size : 0; + file.CreateBy = BoxProviderInfo.Owner; + file.CreateOn = boxFile.CreatedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.CreatedAt.Value) : default; + file.FileStatus = FileStatus.None; + file.FolderID = MakeId(GetParentFolderId(boxFile)); + file.ModifiedBy = BoxProviderInfo.Owner; + file.ModifiedOn = boxFile.ModifiedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.ModifiedAt.Value) : default; + file.NativeAccessor = boxFile; + file.ProviderId = BoxProviderInfo.ID; + file.ProviderKey = BoxProviderInfo.ProviderKey; + file.Title = MakeFileTitle(boxFile); + file.RootFolderId = MakeId(); + file.RootFolderType = BoxProviderInfo.RootFolderType; + file.RootFolderCreator = BoxProviderInfo.Owner; + file.Shared = false; + file.Version = 1; + + return file; + } + + public Folder GetRootFolder(string folderId) + { + return ToFolder(GetBoxFolder("0")); + } + + protected BoxFolder GetBoxFolder(object folderId) + { + var boxFolderId = MakeBoxId(folderId); + try + { + var folder = BoxProviderInfo.GetBoxFolder(boxFolderId); + return folder; + } + catch (Exception ex) + { + return new ErrorFolder(ex, boxFolderId); + } + } + + protected BoxFile GetBoxFile(string fileId) + { + var boxFileId = MakeBoxId(fileId); + try + { + var file = BoxProviderInfo.GetBoxFile(boxFileId); + return file; + } + catch (Exception ex) + { + return new ErrorFile(ex, boxFileId); + } + } + + protected IEnumerable GetChildren(object folderId) + { + return GetBoxItems(folderId).Select(entry => MakeId(entry.Id)); + } + + protected List GetBoxItems(object parentId, bool? folder = null) + { + var boxFolderId = MakeBoxId(parentId); + var items = BoxProviderInfo.GetBoxItems(boxFolderId); + + if (folder.HasValue) + { + if (folder.Value) + { + return items.Where(i => i is BoxFolder).ToList(); + } + + return items.Where(i => i is BoxFile).ToList(); + } + + return items; + } + + protected sealed class ErrorFolder : BoxFolder + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorFolder(Exception e, object id) + { + ErrorId = id.ToString(); + if (e != null) + { + Error = e.Message; + } + } + } + + protected sealed class ErrorFile : BoxFile + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorFile(Exception e, object id) + { + ErrorId = id.ToString(); + if (e != null) + { + Error = e.Message; + } + } + } + + protected string GetAvailableTitle(string requestTitle, string parentFolderId, Func isExist) + { + if (!isExist(requestTitle, parentFolderId)) return requestTitle; + + var re = new Regex(@"( \(((?[0-9])+)\)(\.[^\.]*)?)$"); + var match = re.Match(requestTitle); + + if (!match.Success) + { + var insertIndex = requestTitle.Length; + if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1) + { + insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture); + } + requestTitle = requestTitle.Insert(insertIndex, " (1)"); + } + + while (isExist(requestTitle, parentFolderId)) + { + requestTitle = re.Replace(requestTitle, MatchEvaluator); + } + return requestTitle; + } + + private static string MatchEvaluator(Match match) + { + var index = Convert.ToInt32(match.Groups[2].Value); + var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); + return string.Format(" ({0}){1}", index + 1, staticText); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs new file mode 100644 index 0000000000..edaeabfeec --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs @@ -0,0 +1,176 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxDaoSelector : RegexDaoSelectorBase + { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } + + internal class BoxInfo + { + public BoxProviderInfo BoxProviderInfo { get; set; } + + public string Path { get; set; } + public string PathPrefix { get; set; } + } + + public BoxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) + : base(new Regex(@"^box-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override IFolderDao GetFolderDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ITagDao GetTagDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ISecurityDao GetSecurityDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a Box id"); + } + return base.ConvertId(null); + } + + private BoxInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new BoxInfo + { + Path = match.Groups["path"].Value, + BoxProviderInfo = providerInfo, + PathPrefix = "box-" + match.Groups["id"].Value + }; + } + throw new ArgumentException("Id is not a Box id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private BoxProviderInfo GetProviderInfo(int linkId) + { + BoxProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + try + { + info = (BoxProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(BoxProviderInfo boxProviderInfo, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(boxProviderInfo.ID, newTitle, null, boxProviderInfo.RootFolderType); + boxProviderInfo.UpdateTitle(newTitle); //This will update cached version too + } + } + public static class BoxDaoSelectorExtention + { + public static DIHelper AddBoxDaoSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddBoxSecurityDaoService() + .AddBoxTagDaoService() + .AddBoxFolderDaoService() + .AddBoxFileDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs new file mode 100644 index 0000000000..795411240a --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs @@ -0,0 +1,556 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +using Box.V2.Models; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxFileDao : BoxDaoBase, IFileDao + { + public BoxFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void InvalidateCache(string fileId) + { + var boxFileId = MakeBoxId(fileId); + BoxProviderInfo.CacheReset(boxFileId, true); + + var boxFile = GetBoxFile(fileId); + var parentPath = GetParentFolderId(boxFile); + if (parentPath != null) BoxProviderInfo.CacheReset(parentPath); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ToFile(GetBoxFile(fileId)); + } + + public File GetFile(string parentId, string title) + { + return ToFile(GetBoxItems(parentId, false) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)) as BoxFile); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ToFile(GetBoxFile(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + if (fileIds == null || fileIds.Length == 0) return new List>(); + return fileIds.Select(GetBoxFile).Select(ToFile).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + return GetBoxItems(parentId, false).Select(entry => MakeId(entry.Id)).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = GetBoxItems(parentId, false).Select(item => ToFile(item as BoxFile)); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public Stream GetFileStream(File file, long offset) + { + var boxFileId = MakeBoxId(file.ID); + BoxProviderInfo.CacheReset(boxFileId, true); + + var boxFile = GetBoxFile(file.ID); + if (boxFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + if (boxFile is ErrorFile) throw new Exception(((ErrorFile)boxFile).Error); + + var fileStream = BoxProviderInfo.Storage.DownloadStream(boxFile, (int)offset); + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public File SaveFile(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + if (fileStream == null) throw new ArgumentNullException("fileStream"); + + BoxFile newBoxFile = null; + + if (file.ID != null) + { + var fileId = MakeBoxId(file.ID); + newBoxFile = BoxProviderInfo.Storage.SaveStream(fileId, fileStream); + + if (!newBoxFile.Name.Equals(file.Title)) + { + var folderId = GetParentFolderId(GetBoxFile(fileId)); + file.Title = GetAvailableTitle(file.Title, folderId, IsExist); + newBoxFile = BoxProviderInfo.Storage.RenameFile(fileId, file.Title); + } + } + else if (file.FolderID != null) + { + var folderId = MakeBoxId(file.FolderID); + file.Title = GetAvailableTitle(file.Title, folderId, IsExist); + newBoxFile = BoxProviderInfo.Storage.CreateFile(fileStream, file.Title, folderId); + } + + BoxProviderInfo.CacheReset(newBoxFile); + var parentId = GetParentFolderId(newBoxFile); + if (parentId != null) BoxProviderInfo.CacheReset(parentId); + + return ToFile(newBoxFile); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var boxFile = GetBoxFile(fileId); + if (boxFile == null) return; + var id = MakeId(boxFile.Id); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(boxFile is ErrorFile)) + { + BoxProviderInfo.Storage.DeleteItem(boxFile); + } + + BoxProviderInfo.CacheReset(boxFile.Id, true); + var parentFolderId = GetParentFolderId(boxFile); + if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + } + + public bool IsExist(string title, object folderId) + { + return GetBoxItems(folderId, false) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public string MoveFile(string fileId, string toFolderId) + { + var boxFile = GetBoxFile(fileId); + if (boxFile is ErrorFile) throw new Exception(((ErrorFile)boxFile).Error); + + var toBoxFolder = GetBoxFolder(toFolderId); + if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); + + var fromFolderId = GetParentFolderId(boxFile); + + var newTitle = GetAvailableTitle(boxFile.Name, toBoxFolder.Id, IsExist); + boxFile = BoxProviderInfo.Storage.MoveFile(boxFile.Id, newTitle, toBoxFolder.Id); + + BoxProviderInfo.CacheReset(boxFile.Id, true); + BoxProviderInfo.CacheReset(fromFolderId); + BoxProviderInfo.CacheReset(toBoxFolder.Id); + + return MakeId(boxFile.Id); + } + + public File CopyFile(string fileId, string toFolderId) + { + var boxFile = GetBoxFile(fileId); + if (boxFile is ErrorFile) throw new Exception(((ErrorFile)boxFile).Error); + + var toBoxFolder = GetBoxFolder(toFolderId); + if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); + + var newTitle = GetAvailableTitle(boxFile.Name, toBoxFolder.Id, IsExist); + var newBoxFile = BoxProviderInfo.Storage.CopyFile(boxFile.Id, newTitle, toBoxFolder.Id); + + BoxProviderInfo.CacheReset(newBoxFile); + BoxProviderInfo.CacheReset(toBoxFolder.Id); + + return ToFile(newBoxFile); + } + + public string FileRename(File file, string newTitle) + { + var boxFile = GetBoxFile(file.ID); + newTitle = GetAvailableTitle(newTitle, GetParentFolderId(boxFile), IsExist); + + boxFile = BoxProviderInfo.Storage.RenameFile(boxFile.Id, newTitle); + + BoxProviderInfo.CacheReset(boxFile); + var parentId = GetParentFolderId(boxFile); + if (parentId != null) BoxProviderInfo.CacheReset(parentId); + + return MakeId(boxFile.Id); + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + #region chunking + + private File RestoreIds(File file) + { + if (file == null) return null; + + if (file.ID != null) + file.ID = MakeId(file.ID); + + if (file.FolderID != null) + file.FolderID = MakeId(file.FolderID); + + return file; + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + if (SetupInfo.ChunkUploadSize > contentLength) + return new ChunkedUploadSession(RestoreIds(file), contentLength) { UseChunks = false }; + + var uploadSession = new ChunkedUploadSession(file, contentLength); + + uploadSession.Items["TempPath"] = Path.GetTempFileName(); + + uploadSession.File = RestoreIds(uploadSession.File); + return uploadSession; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, stream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + var tempPath = uploadSession.GetItemOrDefault("TempPath"); + using (var fs = new FileStream(tempPath, FileMode.Append)) + { + stream.CopyTo(fs); + } + + uploadSession.BytesUploaded += chunkLength; + + if (uploadSession.BytesUploaded == uploadSession.BytesTotal) + { + using (var fs = new FileStream(uploadSession.GetItemOrDefault("TempPath"), + FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + uploadSession.File = SaveFile(uploadSession.File, fs); + } + } + else + { + uploadSession.File = RestoreIds(uploadSession.File); + } + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("TempPath")) + { + System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + } + } + + #endregion + + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class BoxFileDaoExtention + { + public static DIHelper AddBoxFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs new file mode 100644 index 0000000000..0b8d6b2a99 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs @@ -0,0 +1,417 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; + +using Box.V2.Models; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxFolderDao : BoxDaoBase, IFolderDao + { + public BoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public Folder GetFolder(string folderId) + { + return ToFolder(GetBoxFolder(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + return ToFolder(GetBoxItems(parentId, true) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)) as BoxFolder); + } + + public Folder GetRootFolderByFile(string fileId) + { + return GetRootFolder(fileId); + } + + public List> GetFolders(string parentId) + { + return GetBoxItems(parentId, true).Select(item => ToFolder(item as BoxFolder)).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); //TODO:!!! + + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateBy) : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.ModifiedOn) : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateOn) : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + + while (folderId != null) + { + var boxFolder = GetBoxFolder(folderId); + + if (boxFolder is ErrorFolder) + { + folderId = null; + } + else + { + path.Add(ToFolder(boxFolder)); + folderId = GetParentFolderId(boxFolder); + } + } + + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + if (folder == null) throw new ArgumentNullException("folder"); + if (folder.ID != null) + { + return RenameFolder(folder, folder.Title); + } + + if (folder.ParentFolderID != null) + { + var boxFolderId = MakeBoxId(folder.ParentFolderID); + + folder.Title = GetAvailableTitle(folder.Title, boxFolderId, IsExist); + + var boxFolder = BoxProviderInfo.Storage.CreateFolder(folder.Title, boxFolderId); + + BoxProviderInfo.CacheReset(boxFolder); + var parentFolderId = GetParentFolderId(boxFolder); + if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + + return MakeId(boxFolder); + } + return null; + } + + public bool IsExist(string title, string folderId) + { + return GetBoxItems(folderId, true) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public void DeleteFolder(string folderId) + { + var boxFolder = GetBoxFolder(folderId); + var id = MakeId(boxFolder); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(boxFolder is ErrorFolder)) + { + BoxProviderInfo.Storage.DeleteItem(boxFolder); + } + + BoxProviderInfo.CacheReset(boxFolder.Id, true); + var parentFolderId = GetParentFolderId(boxFolder); + if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var boxFolder = GetBoxFolder(folderId); + if (boxFolder is ErrorFolder) throw new Exception(((ErrorFolder)boxFolder).Error); + + var toBoxFolder = GetBoxFolder(toFolderId); + if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); + + var fromFolderId = GetParentFolderId(boxFolder); + + var newTitle = GetAvailableTitle(boxFolder.Name, toBoxFolder.Id, IsExist); + boxFolder = BoxProviderInfo.Storage.MoveFolder(boxFolder.Id, newTitle, toBoxFolder.Id); + + BoxProviderInfo.CacheReset(boxFolder.Id, false); + BoxProviderInfo.CacheReset(fromFolderId); + BoxProviderInfo.CacheReset(toBoxFolder.Id); + + return MakeId(boxFolder.Id); + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var boxFolder = GetBoxFolder(folderId); + if (boxFolder is ErrorFolder) throw new Exception(((ErrorFolder)boxFolder).Error); + + var toBoxFolder = GetBoxFolder(toFolderId); + if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); + + var newTitle = GetAvailableTitle(boxFolder.Name, toBoxFolder.Id, IsExist); + var newBoxFolder = BoxProviderInfo.Storage.CopyFolder(boxFolder.Id, newTitle, toBoxFolder.Id); + + BoxProviderInfo.CacheReset(newBoxFolder); + BoxProviderInfo.CacheReset(newBoxFolder.Id, false); + BoxProviderInfo.CacheReset(toBoxFolder.Id); + + return ToFolder(newBoxFolder); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var boxFolder = GetBoxFolder(folder.ID); + var parentFolderId = GetParentFolderId(boxFolder); + + if (IsRoot(boxFolder)) + { + //It's root folder + BoxDaoSelector.RenameProvider(BoxProviderInfo, newTitle); + //rename provider customer title + } + else + { + newTitle = GetAvailableTitle(newTitle, parentFolderId, IsExist); + + //rename folder + boxFolder = BoxProviderInfo.Storage.RenameFolder(boxFolder.Id, newTitle); + } + + BoxProviderInfo.CacheReset(boxFolder); + if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + + return MakeId(boxFolder.Id); + } + + public int GetItemsCount(string folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(string folderId) + { + var boxFolderId = MakeBoxId(folderId); + //note: without cache + return BoxProviderInfo.Storage.GetItems(boxFolderId, 1).Count == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return false; + } + + public bool CanCalculateSubitems(string entryId) + { + return false; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var storageMaxUploadSize = BoxProviderInfo.Storage.GetMaxUploadSize(); + + return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } + + public static class BoxFolderDaoExtention + { + public static DIHelper AddBoxFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs new file mode 100644 index 0000000000..20c3ed0f49 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -0,0 +1,325 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Core.Common.Configuration; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; + +using Box.V2.Models; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.Box +{ + [DebuggerDisplay("{CustomerTitle}")] + internal class BoxProviderInfo : IProviderInfo, IDisposable + { + public OAuth20Token Token { get; set; } + + private string _rootId; + + internal BoxStorage Storage + { + get + { + if (Wrapper.Storage == null || !Wrapper.Storage.IsOpened) + { + return Wrapper.CreateStorage(Token, ID); + } + return Wrapper.Storage; + } + } + + internal bool StorageOpened + { + get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; + } + + public int ID { get; set; } + + public Guid Owner { get; set; } + + public string CustomerTitle { get; set; } + + public DateTime CreateOn { get; set; } + + public string RootFolderId + { + get { return "box-" + ID; } + } + + public string ProviderKey { get; set; } + + public FolderType RootFolderType { get; set; } + + public string BoxRootId + { + get + { + if (string.IsNullOrEmpty(_rootId)) + { + _rootId = Storage.GetRootFolderId(); + } + return _rootId; + } + } + + public BoxStorageDisposableWrapper Wrapper { get; } + public BoxProviderInfoHelper BoxProviderInfoHelper { get; } + + public BoxProviderInfo( + BoxStorageDisposableWrapper wrapper, + BoxProviderInfoHelper boxProviderInfoHelper) + { + Wrapper = wrapper; + BoxProviderInfoHelper = boxProviderInfoHelper; + } + + public void Dispose() + { + if (StorageOpened) + Storage.Close(); + } + + public bool CheckAccess() + { + try + { + return !string.IsNullOrEmpty(BoxRootId); + } + catch (UnauthorizedAccessException) + { + return false; + } + } + + public void InvalidateStorage() + { + if (Wrapper != null) + { + Wrapper.Dispose(); + } + + CacheReset(); + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + + internal BoxFolder GetBoxFolder(string dropboxFolderPath) + { + return BoxProviderInfoHelper.GetBoxFolder(Storage, ID, dropboxFolderPath); + } + + internal BoxFile GetBoxFile(string dropboxFilePath) + { + return BoxProviderInfoHelper.GetBoxFile(Storage, ID, dropboxFilePath); + } + + internal List GetBoxItems(string dropboxFolderPath) + { + return BoxProviderInfoHelper.GetBoxItems(Storage, ID, dropboxFolderPath); + } + + internal void CacheReset(BoxItem boxItem) + { + BoxProviderInfoHelper.CacheReset(ID, boxItem); + } + + internal void CacheReset(string boxPath = null, bool? isFile = null) + { + BoxProviderInfoHelper.CacheReset(BoxRootId, ID, boxPath, isFile); + } + } + + internal class BoxStorageDisposableWrapper : IDisposable + { + public BoxStorage Storage { get; private set; } + public ConsumerFactory ConsumerFactory { get; } + public IServiceProvider ServiceProvider { get; } + + public BoxStorageDisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider) + { + ConsumerFactory = consumerFactory; + ServiceProvider = serviceProvider; + } + + internal BoxStorage CreateStorage(OAuth20Token token, int id) + { + if (Storage != null) return Storage; + + var boxStorage = new BoxStorage(); + CheckToken(token, id); + + boxStorage.Open(token); + return boxStorage; + } + + private void CheckToken(OAuth20Token token, int id) + { + if (token == null) throw new UnauthorizedAccessException("Cannot create Box session with given token"); + if (token.IsExpired) + { + token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, token); + + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(id, new AuthData(token: token.ToJson())); + } + } + + public void Dispose() + { + Storage.Close(); + } + } + + public class BoxProviderInfoHelper + { + private readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1); + private readonly ICache CacheFile = AscCache.Memory; + private readonly ICache CacheFolder = AscCache.Memory; + private readonly ICache CacheChildItems = AscCache.Memory; + private readonly ICacheNotify CacheNotify; + + public BoxProviderInfoHelper(ICacheNotify cacheNotify) + { + CacheNotify = cacheNotify; + CacheNotify.Subscribe((i) => + { + if (i.ResetAll) + { + CacheChildItems.Remove(new Regex("^box-" + i.Key + ".*")); + CacheFile.Remove(new Regex("^boxf-" + i.Key + ".*")); + CacheFolder.Remove(new Regex("^boxd-" + i.Key + ".*")); + } + + if (!i.IsFileExists) + { + CacheChildItems.Remove("box-" + i.Key); + + CacheFolder.Remove("boxd-" + i.Key); + } + else + { + if (i.IsFileExists) + { + CacheFile.Remove("boxf-" + i.Key); + } + else + { + CacheFolder.Remove("boxd-" + i.Key); + } + } + }, CacheNotifyAction.Remove); + } + + internal BoxFolder GetBoxFolder(BoxStorage storage, int id, string boxFolderId) + { + var folder = CacheFolder.Get("boxd-" + id + "-" + boxFolderId); + if (folder == null) + { + folder = storage.GetFolder(boxFolderId); + if (folder != null) + CacheFolder.Insert("boxd-" + id + "-" + boxFolderId, folder, DateTime.UtcNow.Add(CacheExpiration)); + } + return folder; + } + + internal BoxFile GetBoxFile(BoxStorage storage, int id, string boxFileId) + { + var file = CacheFile.Get("boxf-" + id + "-" + boxFileId); + if (file == null) + { + file = storage.GetFile(boxFileId); + if (file != null) + CacheFile.Insert("boxf-" + id + "-" + boxFileId, file, DateTime.UtcNow.Add(CacheExpiration)); + } + return file; + } + + internal List GetBoxItems(BoxStorage storage, int id, string boxFolderId) + { + var items = CacheChildItems.Get>("box-" + id + "-" + boxFolderId); + + if (items == null) + { + items = storage.GetItems(boxFolderId); + CacheChildItems.Insert("box-" + id + "-" + boxFolderId, items, DateTime.UtcNow.Add(CacheExpiration)); + } + return items; + } + + internal void CacheReset(int id, BoxItem boxItem) + { + if (boxItem != null) + { + CacheNotify.Publish(new BoxCacheItem { IsFile = boxItem is BoxFile, Key = id + "-" + boxItem.Id }, CacheNotifyAction.Remove); + } + } + + internal void CacheReset(string boxRootId, int id, string boxId = null, bool? isFile = null) + { + var key = id + "-"; + if (boxId == null) + { + CacheNotify.Publish(new BoxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove); + } + else + { + if (boxId == boxRootId) + { + boxId = "0"; + } + key += boxId; + + CacheNotify.Publish(new BoxCacheItem { IsFile = isFile ?? false, Key = key }, CacheNotifyAction.Remove); + } + } + } + + public static class BoxProviderInfoExtension + { + public static DIHelper AddBoxProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddSingleton(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs new file mode 100644 index 0000000000..0e21941e4d --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs @@ -0,0 +1,99 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxSecurityDao : BoxDaoBase, ISecurityDao + { + public BoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + } + + public static class BoxSecurityDaoExtention + { + public static DIHelper AddBoxSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxStorage.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxStorage.cs new file mode 100644 index 0000000000..af39b04f71 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxStorage.cs @@ -0,0 +1,266 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using ASC.FederatedLogin; +using Box.V2; +using Box.V2.Auth; +using Box.V2.Config; +using Box.V2.Models; +using BoxSDK = Box.V2; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxStorage + { + private OAuth20Token _token; + + private BoxClient _boxClient; + + private readonly List _boxFields = new List { "created_at", "modified_at", "name", "parent", "size" }; + + public bool IsOpened { get; private set; } + + public long MaxChunkedUploadFileSize = 250L*1024L*1024L; + + public void Open(OAuth20Token token) + { + if (IsOpened) + return; + + _token = token; + + var config = new BoxConfig(_token.ClientID, _token.ClientSecret, new Uri(_token.RedirectUri)); + var session = new OAuthSession(_token.AccessToken, _token.RefreshToken, (int)_token.ExpiresIn, "bearer"); + _boxClient = new BoxClient(config, session); + + IsOpened = true; + } + + public void Close() + { + IsOpened = false; + } + + + public string GetRootFolderId() + { + var root = GetFolder("0"); + + return root.Id; + } + + public BoxFolder GetFolder(string folderId) + { + try + { + return _boxClient.FoldersManager.GetInformationAsync(folderId, _boxFields).Result; + } + catch (Exception ex) + { + var boxException = (BoxSDK.Exceptions.BoxException)ex.InnerException; + if (boxException != null && boxException.Error.Status == ((int)HttpStatusCode.NotFound).ToString()) + { + return null; + } + throw; + } + } + + public BoxFile GetFile(string fileId) + { + try + { + return _boxClient.FilesManager.GetInformationAsync(fileId, _boxFields).Result; + } + catch (Exception ex) + { + var boxException = (BoxSDK.Exceptions.BoxException)ex.InnerException; + if (boxException != null && boxException.Error.Status == ((int)HttpStatusCode.NotFound).ToString()) + { + return null; + } + throw; + } + } + + public List GetItems(string folderId, int limit = 500) + { + return _boxClient.FoldersManager.GetFolderItemsAsync(folderId, limit, 0, _boxFields).Result.Entries; + } + + public Stream DownloadStream(BoxFile file, int offset = 0) + { + if (file == null) throw new ArgumentNullException("file"); + + if (offset > 0 && file.Size.HasValue) + { + return _boxClient.FilesManager.DownloadStreamAsync(file.Id, startOffsetInBytes: offset, endOffsetInBytes: (int)file.Size - 1).Result; + } + + var str = _boxClient.FilesManager.DownloadStreamAsync(file.Id).Result; + if (offset == 0) + { + return str; + } + + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + if (str != null) + { + str.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(offset, SeekOrigin.Begin); + + str.Dispose(); + } + + return tempBuffer; + } + + public BoxFolder CreateFolder(string title, string parentId) + { + var boxFolderRequest = new BoxFolderRequest + { + Name = title, + Parent = new BoxRequestEntity + { + Id = parentId + } + }; + return _boxClient.FoldersManager.CreateAsync(boxFolderRequest, _boxFields).Result; + } + + public BoxFile CreateFile(Stream fileStream, string title, string parentId) + { + var boxFileRequest = new BoxFileRequest + { + Name = title, + Parent = new BoxRequestEntity + { + Id = parentId + } + }; + return _boxClient.FilesManager.UploadAsync(boxFileRequest, fileStream, _boxFields, setStreamPositionToZero: false).Result; + } + + public void DeleteItem(BoxItem boxItem) + { + if (boxItem is BoxFolder) + { + _boxClient.FoldersManager.DeleteAsync(boxItem.Id, true).Wait(); + } + else + { + _boxClient.FilesManager.DeleteAsync(boxItem.Id).Wait(); + } + } + + public BoxFolder MoveFolder(string boxFolderId, string newFolderName, string toFolderId) + { + var boxFolderRequest = new BoxFolderRequest + { + Id = boxFolderId, + Name = newFolderName, + Parent = new BoxRequestEntity + { + Id = toFolderId + } + }; + return _boxClient.FoldersManager.UpdateInformationAsync(boxFolderRequest, _boxFields).Result; + } + + public BoxFile MoveFile(string boxFileId, string newFileName, string toFolderId) + { + var boxFileRequest = new BoxFileRequest + { + Id = boxFileId, + Name = newFileName, + Parent = new BoxRequestEntity + { + Id = toFolderId + } + }; + return _boxClient.FilesManager.UpdateInformationAsync(boxFileRequest, null, _boxFields).Result; + } + + public BoxFolder CopyFolder(string boxFolderId, string newFolderName, string toFolderId) + { + var boxFolderRequest = new BoxFolderRequest + { + Id = boxFolderId, + Name = newFolderName, + Parent = new BoxRequestEntity + { + Id = toFolderId + } + }; + return _boxClient.FoldersManager.CopyAsync(boxFolderRequest, _boxFields).Result; + } + + public BoxFile CopyFile(string boxFileId, string newFileName, string toFolderId) + { + var boxFileRequest = new BoxFileRequest + { + Id = boxFileId, + Name = newFileName, + Parent = new BoxRequestEntity + { + Id = toFolderId + } + }; + return _boxClient.FilesManager.CopyAsync(boxFileRequest, _boxFields).Result; + } + + public BoxFolder RenameFolder(string boxFolderId, string newName) + { + var boxFolderRequest = new BoxFolderRequest { Id = boxFolderId, Name = newName }; + return _boxClient.FoldersManager.UpdateInformationAsync(boxFolderRequest, _boxFields).Result; + } + + public BoxFile RenameFile(string boxFileId, string newName) + { + var boxFileRequest = new BoxFileRequest { Id = boxFileId, Name = newName }; + return _boxClient.FilesManager.UpdateInformationAsync(boxFileRequest, null, _boxFields).Result; + } + + public BoxFile SaveStream(string fileId, Stream fileStream) + { + return _boxClient.FilesManager.UploadNewVersionAsync(null, fileId, fileStream, fields: _boxFields, setStreamPositionToZero: false).Result; + } + + public long GetMaxUploadSize() + { + var boxUser = _boxClient.UsersManager.GetCurrentUserInformationAsync(new[] { "max_upload_size" }).Result; + var max = boxUser.MaxUploadSize.HasValue ? boxUser.MaxUploadSize.Value : MaxChunkedUploadFileSize; + + //todo: without chunked uploader: + return Math.Min(max, MaxChunkedUploadFileSize); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs new file mode 100644 index 0000000000..0b78f8a8df --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs @@ -0,0 +1,176 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.Box +{ + internal class BoxTagDao : BoxDaoBase, ITagDao + { + public BoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + #region ITagDao Members + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + var folderId = BoxDaoSelector.ConvertId(parentFolder.ID); + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(GetChildren(folderId)); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return null; + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return null; + } + + public IEnumerable SaveTags(Tag tag) + { + return null; + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return null; + } + + public void MarkAsNew(Guid subject, FileEntry fileEntry) + { + } + + #endregion + } + + public static class BoxTagDaoExtention + { + public static DIHelper AddBoxTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index 183e9aaa2b..b2f55f471e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -93,9 +93,9 @@ namespace ASC.Files.Thirdparty.Dropbox if (id == null) return null; string result; - if (id.ToString().StartsWith("dropbox")) + if (id.StartsWith("dropbox")) { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id, HashAlg.MD5)), "-", "").ToLower(); } else { diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs index 0935e75536..2230f7bc65 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs @@ -29,7 +29,6 @@ using System.Globalization; using System.Text.RegularExpressions; using ASC.Common; -using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Security; @@ -40,7 +39,6 @@ namespace ASC.Files.Thirdparty.Dropbox internal class DropboxDaoSelector : RegexDaoSelectorBase { public IServiceProvider ServiceProvider { get; } - public TenantManager TenantManager { get; } public IDaoFactory DaoFactory { get; } internal class DropboxInfo @@ -51,11 +49,10 @@ namespace ASC.Files.Thirdparty.Dropbox public string PathPrefix { get; set; } } - public DropboxDaoSelector(IServiceProvider serviceProvider, TenantManager tenantManager, IDaoFactory daoFactory) + public DropboxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) : base(new Regex(@"^dropbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) { ServiceProvider = serviceProvider; - TenantManager = tenantManager; DaoFactory = daoFactory; } @@ -159,12 +156,9 @@ namespace ASC.Files.Thirdparty.Dropbox public void RenameProvider(DropboxProviderInfo dropboxProviderInfo, string newTitle) { - //TODO - //using (var dbDao = new CachedProviderAccountDao(TenantManager.GetCurrentTenant().TenantId, FileConstant.DatabaseId)) - //{ - // dbDao.UpdateProviderInfo(dropboxProviderInfo.ID, newTitle, null, dropboxProviderInfo.RootFolderType); - // dropboxProviderInfo.UpdateTitle(newTitle); //This will update cached version too - //} + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(dropboxProviderInfo.ID, newTitle, null, dropboxProviderInfo.RootFolderType); + dropboxProviderInfo.UpdateTitle(newTitle); //This will update cached version too } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index ef753ddded..09c5385ebe 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -57,13 +57,10 @@ namespace ASC.Files.Thirdparty.Dropbox internal bool StorageOpened { - get - { - return Wrapper.Storage != null && Wrapper.Storage.IsOpened; - } + get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; } - public StorageDisposableWrapper Wrapper { get; } + public DropboxStorageDisposableWrapper Wrapper { get; } public DropboxProviderInfoHelper DropboxProviderInfoHelper { get; } public int ID { get; set; } @@ -84,7 +81,7 @@ namespace ASC.Files.Thirdparty.Dropbox public DropboxProviderInfo( - StorageDisposableWrapper wrapper, + DropboxStorageDisposableWrapper wrapper, DropboxProviderInfoHelper dropboxProviderInfoHelper ) { @@ -152,12 +149,12 @@ namespace ASC.Files.Thirdparty.Dropbox } } - internal class StorageDisposableWrapper : IDisposable + internal class DropboxStorageDisposableWrapper : IDisposable { public DropboxStorage Storage { get; private set; } - public StorageDisposableWrapper() + public DropboxStorageDisposableWrapper() { } @@ -286,7 +283,7 @@ namespace ASC.Files.Thirdparty.Dropbox public static DIHelper AddDropboxProviderInfoService(this DIHelper services) { services.TryAddScoped(); - services.TryAddScoped(); + services.TryAddScoped(); services.TryAddSingleton(); return services; diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs index e59ec99ced..11b8446c63 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs @@ -80,7 +80,6 @@ namespace ASC.Files.Thirdparty.Dropbox if (!entryIDs.Any()) return new List(); - //TODO var q = FilesDbContext.Tag .Join(FilesDbContext.TagLink.DefaultIfEmpty(), r => new TagLink { TenantId = r.TenantId, Id = r.Id }, @@ -163,26 +162,26 @@ namespace ASC.Files.Thirdparty.Dropbox { } - #endregion + #endregion + } - public class TagLink + public class TagLink + { + public int TenantId { get; set; } + public int Id { get; set; } + } + + public class TagLinkComparer : IEqualityComparer + { + public bool Equals([AllowNull] TagLink x, [AllowNull] TagLink y) { - public int TenantId { get; set; } - public int Id { get; set; } + return x.Id == y.Id && x.TenantId == y.TenantId; } - public class TagLinkComparer : IEqualityComparer + public int GetHashCode([DisallowNull] TagLink obj) { - 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(); - } - } + return obj.Id.GetHashCode() + obj.TenantId.GetHashCode(); + } } public static class DropboxTagDaoExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index 6fa8961660..12b2e6407a 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -40,6 +40,7 @@ using ASC.FederatedLogin.LoginProviders; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Resources; +using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; @@ -373,17 +374,18 @@ namespace ASC.Files.Thirdparty var folderType = input.FolderType; var createOn = TenantUtil.DateTimeFromUtc(input.CreateOn); - //if (key == ProviderTypes.Box) - //{ - // return new BoxProviderInfo( - // id, - // key.ToString(), - // providerTitle, - // token, - // owner, - // folderType, - // createOn); - //} + if (key == ProviderTypes.Box) + { + var box = ServiceProvider.GetService(); + box.ID = id; + box.CustomerTitle = providerTitle; + box.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + box.ProviderKey = input.Provider; + box.RootFolderType = folderType; + box.CreateOn = createOn; + box.Token = OAuth20Token.FromJson(token); + return box; + } if (key == ProviderTypes.DropboxV2) { @@ -568,6 +570,7 @@ namespace ASC.Files.Thirdparty //services.TryAddScoped(); return services + .AddBoxProviderInfoService() .AddDropboxProviderInfoService() .AddTenantUtilService() .AddTenantManagerService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index 280933f75e..a1a431c7d9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -33,6 +33,7 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Resources; +using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; using ASC.Web.Files.Utils; using ASC.Web.Studio.Core; @@ -65,7 +66,7 @@ namespace ASC.Files.Thirdparty.ProviderDao //Selectors.Add(new SharpBoxDaoSelector()); //Selectors.Add(new SharePointDaoSelector()); //Selectors.Add(new GoogleDriveDaoSelector()); - //Selectors.Add(new BoxDaoSelector()); + ServiceProvider.GetService(), ServiceProvider.GetService() }; // Selectors.Add(new OneDriveDaoSelector()); @@ -264,7 +265,8 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderDaoBaseService(this DIHelper services) { return services - .AddDropboxDaoSelectorService(); + .AddDropboxDaoSelectorService() + .AddBoxDaoSelectorService(); } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/proto/BoxCacheItem.proto b/products/ASC.Files/Server/proto/BoxCacheItem.proto new file mode 100644 index 0000000000..7ed236736d --- /dev/null +++ b/products/ASC.Files/Server/proto/BoxCacheItem.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty.Box; + +message BoxCacheItem { + bool ResetAll = 1; + bool IsFile = 2; + bool IsFileExists = 3; + string Key = 4; +} \ No newline at end of file From c7dab9943f4e1240bbe68c7955cb3656ad128022 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Thu, 12 Mar 2020 14:29:36 +0300 Subject: [PATCH 11/30] Files: GoogleDrive --- products/ASC.Files/Server/ASC.Files.csproj | 3 + .../Core/Thirdparty/Box/BoxProviderInfo.cs | 2 +- .../GoogleDrive/GoogleDriveDaoBase.cs | 391 ++++++++++++ .../GoogleDrive/GoogleDriveDaoSelector.cs | 178 ++++++ .../GoogleDrive/GoogleDriveFileDao.cs | 596 ++++++++++++++++++ .../GoogleDrive/GoogleDriveFolderDao.cs | 408 ++++++++++++ .../GoogleDrive/GoogleDriveProviderInfo.cs | 377 +++++++++++ .../GoogleDrive/GoogleDriveSecurityDao.cs | 100 +++ .../GoogleDrive/GoogleDriveStorage.cs | 514 +++++++++++++++ .../GoogleDrive/GoogleDriveTagDao.cs | 177 ++++++ .../Core/Thirdparty/ProviderAccountDao.cs | 2 + .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 5 +- .../Server/proto/GoogleDriveCacheItem.proto | 12 + 13 files changed, 2762 insertions(+), 3 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs create mode 100644 products/ASC.Files/Server/proto/GoogleDriveCacheItem.proto diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index 42ccd75603..4fa6e7c371 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -21,6 +21,7 @@ + @@ -28,6 +29,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -46,6 +48,7 @@ + diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs index 20c3ed0f49..187d93f953 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -306,7 +306,7 @@ namespace ASC.Files.Thirdparty.Box } key += boxId; - CacheNotify.Publish(new BoxCacheItem { IsFile = isFile ?? false, Key = key }, CacheNotifyAction.Remove); + CacheNotify.Publish(new BoxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove); } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs new file mode 100644 index 0000000000..64e9d69479 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs @@ -0,0 +1,391 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Common.Web; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Security.Cryptography; +using ASC.Web.Core.Files; +using ASC.Web.Files.Classes; +using ASC.Web.Studio.Core; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +using DriveFile = Google.Apis.Drive.v3.Data.File; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal abstract class GoogleDriveDaoBase + { + public GoogleDriveDaoSelector GoogleDriveDaoSelector { get; set; } + + public int TenantID { get; set; } + public GoogleDriveProviderInfo GoogleDriveProviderInfo { get; set; } + public string PathPrefix { get; set; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantManager TenantManager { get; } + public TenantUtil TenantUtil { get; } + public FilesDbContext FilesDbContext { get; } + public SetupInfo SetupInfo { get; } + public FileUtility FileUtility { get; } + + public GoogleDriveDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + FileUtility fileUtility) + { + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantManager = tenantManager; + TenantUtil = tenantUtil; + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + SetupInfo = setupInfo; + FileUtility = fileUtility; + } + + public void Init(GoogleDriveDaoSelector.GoogleDriveInfo googleDriveInfo, GoogleDriveDaoSelector googleDriveDaoSelector) + { + GoogleDriveProviderInfo = googleDriveInfo.GoogleDriveProviderInfo; + PathPrefix = googleDriveInfo.PathPrefix; + GoogleDriveDaoSelector = googleDriveDaoSelector; + } + + public void Dispose() + { + GoogleDriveProviderInfo.Dispose(); + } + + protected string MappingID(string id, bool saveIfNotExist = false) + { + if (id == null) return null; + + string result; + if (id.ToString().StartsWith("drive")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + + return result; + } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + + protected static string MakeDriveId(object entryId) + { + var id = Convert.ToString(entryId, CultureInfo.InvariantCulture); + return string.IsNullOrEmpty(id) + ? "root" + : id.TrimStart('/'); + } + + protected static string GetParentDriveId(DriveFile driveEntry) + { + return driveEntry == null || driveEntry.Parents == null || driveEntry.Parents.Count == 0 + ? null + : driveEntry.Parents[0]; + } + + protected string MakeId(DriveFile driveEntry) + { + var path = string.Empty; + if (driveEntry != null) + { + path = IsRoot(driveEntry) ? "root" : driveEntry.Id; + } + + return MakeId(path); + } + + protected string MakeId(string path = null) + { + return string.Format("{0}{1}", PathPrefix, + string.IsNullOrEmpty(path) || path == "root" || path == GoogleDriveProviderInfo.DriveRootId + ? "" : ("-|" + path.TrimStart('/'))); + } + + protected string MakeFolderTitle(DriveFile driveFolder) + { + if (driveFolder == null || IsRoot(driveFolder)) + { + return GoogleDriveProviderInfo.CustomerTitle; + } + + return Global.ReplaceInvalidCharsAndTruncate(driveFolder.Name); + } + + protected string MakeFileTitle(DriveFile driveFile) + { + if (driveFile == null || string.IsNullOrEmpty(driveFile.Name)) + { + return GoogleDriveProviderInfo.ProviderKey; + } + + var title = driveFile.Name; + + var gExt = MimeMapping.GetExtention(driveFile.MimeType); + if (GoogleLoginProvider.GoogleDriveExt.Contains(gExt)) + { + var downloadableExtension = FileUtility.GetGoogleDownloadableExtension(gExt); + if (!downloadableExtension.Equals(FileUtility.GetFileExtension(title))) + { + title += downloadableExtension; + } + } + + return Global.ReplaceInvalidCharsAndTruncate(title); + } + + protected Folder ToFolder(DriveFile driveEntry) + { + if (driveEntry == null) return null; + if (driveEntry is ErrorDriveEntry) + { + //Return error entry + return ToErrorFolder(driveEntry as ErrorDriveEntry); + } + + if (driveEntry.MimeType != GoogleLoginProvider.GoogleDriveMimeTypeFolder) + { + return null; + } + + var isRoot = IsRoot(driveEntry); + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(driveEntry); + folder.ParentFolderID = isRoot ? null : MakeId(GetParentDriveId(driveEntry)); + folder.CreateBy = GoogleDriveProviderInfo.Owner; + folder.CreateOn = isRoot ? GoogleDriveProviderInfo.CreateOn : (driveEntry.CreatedTime ?? default); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = GoogleDriveProviderInfo.Owner; + folder.ModifiedOn = isRoot ? GoogleDriveProviderInfo.CreateOn : (driveEntry.ModifiedTime ?? default); + folder.ProviderId = GoogleDriveProviderInfo.ID; + folder.ProviderKey = GoogleDriveProviderInfo.ProviderKey; + folder.RootFolderCreator = GoogleDriveProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + + folder.Shareable = false; + folder.Title = MakeFolderTitle(driveEntry); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + + if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) + folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); + + if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc) + folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn); + + return folder; + } + + protected static bool IsRoot(DriveFile driveFolder) + { + return IsDriveFolder(driveFolder) && GetParentDriveId(driveFolder) == null; + } + + private static bool IsDriveFolder(DriveFile driveFolder) + { + return driveFolder != null && driveFolder.MimeType == GoogleLoginProvider.GoogleDriveMimeTypeFolder; + } + + private File ToErrorFile(ErrorDriveEntry driveEntry) + { + if (driveEntry == null) return null; + + var file = ServiceProvider.GetService>(); + file.ID = MakeId(driveEntry.ErrorId); + file.CreateBy = GoogleDriveProviderInfo.Owner; + file.CreateOn = TenantUtil.DateTimeNow(); + file.ModifiedBy = GoogleDriveProviderInfo.Owner; + file.ModifiedOn = TenantUtil.DateTimeNow(); + file.ProviderId = GoogleDriveProviderInfo.ID; + file.ProviderKey = GoogleDriveProviderInfo.ProviderKey; + file.RootFolderCreator = GoogleDriveProviderInfo.Owner; + file.RootFolderId = MakeId(); + file.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + file.Title = MakeFileTitle(driveEntry); + file.Error = driveEntry.Error; + + return file; + } + + private Folder ToErrorFolder(ErrorDriveEntry driveEntry) + { + if (driveEntry == null) return null; + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(driveEntry.ErrorId); + folder.ParentFolderID = null; + folder.CreateBy = GoogleDriveProviderInfo.Owner; + folder.CreateOn = TenantUtil.DateTimeNow(); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = GoogleDriveProviderInfo.Owner; + folder.ModifiedOn = TenantUtil.DateTimeNow(); + folder.ProviderId = GoogleDriveProviderInfo.ID; + folder.ProviderKey = GoogleDriveProviderInfo.ProviderKey; + folder.RootFolderCreator = GoogleDriveProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeFolderTitle(driveEntry); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + folder.Error = driveEntry.Error; + + return folder; + } + + public File ToFile(DriveFile driveFile) + { + if (driveFile == null) return null; + + if (driveFile is ErrorDriveEntry) + { + //Return error entry + return ToErrorFile(driveFile as ErrorDriveEntry); + } + + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(driveFile.Id); + file.Access = FileShare.None; + file.ContentLength = driveFile.Size.HasValue ? (long)driveFile.Size : 0; + file.CreateBy = GoogleDriveProviderInfo.Owner; + file.CreateOn = driveFile.CreatedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.CreatedTime.Value) : default(DateTime); + file.FileStatus = FileStatus.None; + file.FolderID = MakeId(GetParentDriveId(driveFile)); + file.ModifiedBy = GoogleDriveProviderInfo.Owner; + file.ModifiedOn = driveFile.ModifiedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.ModifiedTime.Value) : default(DateTime); + file.NativeAccessor = driveFile; + file.ProviderId = GoogleDriveProviderInfo.ID; + file.ProviderKey = GoogleDriveProviderInfo.ProviderKey; + file.Title = MakeFileTitle(driveFile); + file.RootFolderId = MakeId(); + file.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + file.RootFolderCreator = GoogleDriveProviderInfo.Owner; + file.Shared = false; + file.Version = 1; + + return file; + } + + public Folder GetRootFolder(string folderId) + { + return ToFolder(GetDriveEntry("")); + } + + protected DriveFile GetDriveEntry(string entryId) + { + var driveId = MakeDriveId(entryId); + try + { + var entry = GoogleDriveProviderInfo.GetDriveEntry(driveId); + return entry; + } + catch (Exception ex) + { + return new ErrorDriveEntry(ex, driveId); + } + } + + protected IEnumerable GetChildren(object folderId) + { + return GetDriveEntries(folderId).Select(entry => MakeId(entry.Id)); + } + + protected List GetDriveEntries(object parentId, bool? folder = null) + { + var parentDriveId = MakeDriveId(parentId); + var entries = GoogleDriveProviderInfo.GetDriveEntries(parentDriveId, folder); + return entries; + } + + + protected sealed class ErrorDriveEntry : DriveFile + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorDriveEntry(Exception e, object id) + { + ErrorId = id.ToString(); + if (id.ToString() == "root") + { + MimeType = GoogleLoginProvider.GoogleDriveMimeTypeFolder; + } + if (e != null) + { + Error = e.Message; + } + } + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs new file mode 100644 index 0000000000..59866b68a0 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs @@ -0,0 +1,178 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveDaoSelector : RegexDaoSelectorBase + { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } + + internal class GoogleDriveInfo + { + public GoogleDriveProviderInfo GoogleDriveProviderInfo { get; set; } + + public string Path { get; set; } + public string PathPrefix { get; set; } + } + + public GoogleDriveDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) + : base(new Regex(@"^drive-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override IFolderDao GetFolderDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ITagDao GetTagDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ISecurityDao GetSecurityDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a GoogleDrive id"); + } + return base.ConvertId(null); + } + + private GoogleDriveInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new GoogleDriveInfo + { + Path = match.Groups["path"].Value, + GoogleDriveProviderInfo = providerInfo, + PathPrefix = "drive-" + match.Groups["id"].Value + }; + } + throw new ArgumentException("Id is not a GoogleDrive id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private GoogleDriveProviderInfo GetProviderInfo(int linkId) + { + GoogleDriveProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + + try + { + info = (GoogleDriveProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(GoogleDriveProviderInfo googleDriveProviderInfo, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(googleDriveProviderInfo.ID, newTitle, null, googleDriveProviderInfo.RootFolderType); + googleDriveProviderInfo.UpdateTitle(newTitle); //This will update cached version too + } + } + + public static class GoogleDriveDaoSelectorExtention + { + public static DIHelper AddGoogleDriveSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddGoogleDriveSecurityDaoService() + .AddGoogleDriveTagDaoService() + .AddGoogleDriveFolderDaoService() + .AddGoogleDriveFileDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs new file mode 100644 index 0000000000..6a8c00d123 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -0,0 +1,596 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +using DriveFile = Google.Apis.Drive.v3.Data.File; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao + { + public GoogleDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + { + } + + public void InvalidateCache(string fileId) + { + var driveId = MakeDriveId(fileId); + GoogleDriveProviderInfo.CacheReset(driveId, true); + + var driveFile = GetDriveEntry(fileId); + var parentDriveId = GetParentDriveId(driveFile); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ToFile(GetDriveEntry(fileId)); + } + + public File GetFile(string parentId, string title) + { + return ToFile(GetDriveEntries(parentId, false) + .FirstOrDefault(file => file.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase))); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ToFile(GetDriveEntry(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + if (fileIds == null || fileIds.Length == 0) return new List>(); + return fileIds.Select(GetDriveEntry).Select(ToFile).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + return GetDriveEntries(parentId, false).Select(entry => MakeId(entry.Id)).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = GetDriveEntries(parentId, false).Select(ToFile); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public Stream GetFileStream(File file, long offset) + { + var driveId = MakeDriveId(file.ID); + GoogleDriveProviderInfo.CacheReset(driveId, true); + var driveFile = GetDriveEntry(file.ID); + if (driveFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + if (driveFile is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFile).Error); + + var fileStream = GoogleDriveProviderInfo.Storage.DownloadStream(driveFile, (int)offset); + + if (!driveFile.Size.HasValue && fileStream != null && fileStream.CanSeek) + { + file.ContentLength = fileStream.Length; // hack for google drive + } + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public File SaveFile(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + if (fileStream == null) throw new ArgumentNullException("fileStream"); + + DriveFile newDriveFile = null; + + if (file.ID != null) + { + newDriveFile = GoogleDriveProviderInfo.Storage.SaveStream(MakeDriveId(file.ID), fileStream, file.Title); + } + else if (file.FolderID != null) + { + newDriveFile = GoogleDriveProviderInfo.Storage.InsertEntry(fileStream, file.Title, MakeDriveId(file.FolderID)); + } + + GoogleDriveProviderInfo.CacheReset(newDriveFile); + var parentDriveId = GetParentDriveId(newDriveFile); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + + return ToFile(newDriveFile); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var driveFile = GetDriveEntry(fileId); + if (driveFile == null) return; + var id = MakeId(driveFile.Id); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(driveFile is ErrorDriveEntry)) + { + GoogleDriveProviderInfo.Storage.DeleteEntry(driveFile.Id); + } + + GoogleDriveProviderInfo.CacheReset(driveFile.Id); + var parentDriveId = GetParentDriveId(driveFile); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + } + + public bool IsExist(string title, object folderId) + { + return GetDriveEntries(folderId, false) + .Any(file => file.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public string MoveFile(string fileId, string toFolderId) + { + var driveFile = GetDriveEntry(fileId); + if (driveFile is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFile).Error); + + var toDriveFolder = GetDriveEntry(toFolderId); + if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); + + var fromFolderDriveId = GetParentDriveId(driveFile); + + driveFile = GoogleDriveProviderInfo.Storage.InsertEntryIntoFolder(driveFile, toDriveFolder.Id); + if (fromFolderDriveId != null) + { + GoogleDriveProviderInfo.Storage.RemoveEntryFromFolder(driveFile, fromFolderDriveId); + } + + GoogleDriveProviderInfo.CacheReset(driveFile.Id); + GoogleDriveProviderInfo.CacheReset(fromFolderDriveId, false); + GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, false); + + return MakeId(driveFile.Id); + } + + public File CopyFile(string fileId, string toFolderId) + { + var driveFile = GetDriveEntry(fileId); + if (driveFile is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFile).Error); + + var toDriveFolder = GetDriveEntry(toFolderId); + if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); + + var newDriveFile = GoogleDriveProviderInfo.Storage.CopyEntry(toDriveFolder.Id, driveFile.Id); + + GoogleDriveProviderInfo.CacheReset(newDriveFile); + GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, false); + + return ToFile(newDriveFile); + } + + public string FileRename(File file, string newTitle) + { + var driveFile = GetDriveEntry(file.ID); + driveFile.Name = newTitle; + + driveFile = GoogleDriveProviderInfo.Storage.RenameEntry(driveFile.Id, driveFile.Name); + + GoogleDriveProviderInfo.CacheReset(driveFile); + var parentDriveId = GetParentDriveId(driveFile); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + + return MakeId(driveFile.Id); + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + #region chunking + + private File RestoreIds(File file) + { + if (file == null) return null; + + if (file.ID != null) + file.ID = MakeId(file.ID); + + if (file.FolderID != null) + file.FolderID = MakeId(file.FolderID); + + return file; + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + if (SetupInfo.ChunkUploadSize > contentLength) + return new ChunkedUploadSession(RestoreIds(file), contentLength) { UseChunks = false }; + + var uploadSession = new ChunkedUploadSession(file, contentLength); + + DriveFile driveFile; + if (file.ID != null) + { + driveFile = GetDriveEntry(file.ID); + } + else + { + var folder = GetDriveEntry(file.FolderID); + driveFile = GoogleDriveProviderInfo.Storage.FileConstructor(file.Title, null, folder.Id); + } + + var googleDriveSession = GoogleDriveProviderInfo.Storage.CreateResumableSession(driveFile, contentLength); + if (googleDriveSession != null) + { + uploadSession.Items["GoogleDriveSession"] = googleDriveSession; + } + else + { + uploadSession.Items["TempPath"] = Path.GetTempFileName(); + } + + uploadSession.File = RestoreIds(uploadSession.File); + return uploadSession; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, stream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + if (uploadSession.Items.ContainsKey("GoogleDriveSession")) + { + var googleDriveSession = uploadSession.GetItemOrDefault("GoogleDriveSession"); + GoogleDriveProviderInfo.Storage.Transfer(googleDriveSession, stream, chunkLength); + } + else + { + var tempPath = uploadSession.GetItemOrDefault("TempPath"); + using (var fs = new FileStream(tempPath, FileMode.Append)) + { + stream.CopyTo(fs); + } + } + + uploadSession.BytesUploaded += chunkLength; + + if (uploadSession.BytesUploaded == uploadSession.BytesTotal) + { + uploadSession.File = FinalizeUploadSession(uploadSession); + } + else + { + uploadSession.File = RestoreIds(uploadSession.File); + } + } + + public File FinalizeUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("GoogleDriveSession")) + { + var googleDriveSession = uploadSession.GetItemOrDefault("GoogleDriveSession"); + + GoogleDriveProviderInfo.CacheReset(googleDriveSession.FileId); + var parentDriveId = googleDriveSession.FolderId; + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + + return ToFile(GetDriveEntry(googleDriveSession.FileId)); + } + + using (var fs = new FileStream(uploadSession.GetItemOrDefault("TempPath"), FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + return SaveFile(uploadSession.File, fs); + } + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("GoogleDriveSession")) + { + var googleDriveSession = uploadSession.GetItemOrDefault("GoogleDriveSession"); + + if (googleDriveSession.Status != ResumableUploadSessionStatus.Completed) + { + googleDriveSession.Status = ResumableUploadSessionStatus.Aborted; + } + } + else if (uploadSession.Items.ContainsKey("TempPath")) + { + System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + } + } + + #endregion + + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + return null; + } + + #endregion + } + + public static class GoogleDriveFilrDaoExtention + { + public static DIHelper AddGoogleDriveFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs new file mode 100644 index 0000000000..f7a5cb3b33 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs @@ -0,0 +1,408 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Web.Core.Files; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveFolderDao : GoogleDriveDaoBase, IFolderDao + { + public GoogleDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + { + } + + public Folder GetFolder(string folderId) + { + return ToFolder(GetDriveEntry(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + return ToFolder(GetDriveEntries(parentId, true) + .FirstOrDefault(folder => folder.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase))); + } + + public Folder GetRootFolderByFile(string fileId) + { + return GetRootFolder(""); + } + + public List> GetFolders(string parentId) + { + return GetDriveEntries(parentId, true).Select(ToFolder).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); //TODO:!!! + + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateBy) : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.ModifiedOn) : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateOn) : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + + while (folderId != null) + { + var driveFolder = GetDriveEntry(folderId); + + if (driveFolder is ErrorDriveEntry) + { + folderId = null; + } + else + { + path.Add(ToFolder(driveFolder)); + folderId = GetParentDriveId(driveFolder); + } + } + + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + if (folder == null) throw new ArgumentNullException("folder"); + if (folder.ID != null) + { + return RenameFolder(folder, folder.Title); + } + + if (folder.ParentFolderID != null) + { + var driveFolderId = MakeDriveId(folder.ParentFolderID); + + var driveFolder = GoogleDriveProviderInfo.Storage.InsertEntry(null, folder.Title, driveFolderId, true); + + GoogleDriveProviderInfo.CacheReset(driveFolder); + var parentDriveId = GetParentDriveId(driveFolder); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + + return MakeId(driveFolder); + } + return null; + } + + public void DeleteFolder(string folderId) + { + var driveFolder = GetDriveEntry(folderId); + var id = MakeId(driveFolder); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(driveFolder is ErrorDriveEntry)) + GoogleDriveProviderInfo.Storage.DeleteEntry(driveFolder.Id); + + GoogleDriveProviderInfo.CacheReset(driveFolder.Id); + var parentDriveId = GetParentDriveId(driveFolder); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var driveFolder = GetDriveEntry(folderId); + if (driveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFolder).Error); + + var toDriveFolder = GetDriveEntry(toFolderId); + if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); + + var fromFolderDriveId = GetParentDriveId(driveFolder); + + driveFolder = GoogleDriveProviderInfo.Storage.InsertEntryIntoFolder(driveFolder, toDriveFolder.Id); + if (fromFolderDriveId != null) + { + GoogleDriveProviderInfo.Storage.RemoveEntryFromFolder(driveFolder, fromFolderDriveId); + } + + GoogleDriveProviderInfo.CacheReset(driveFolder.Id); + GoogleDriveProviderInfo.CacheReset(fromFolderDriveId, true); + GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, true); + + return MakeId(driveFolder.Id); + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var driveFolder = GetDriveEntry(folderId); + if (driveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFolder).Error); + + var toDriveFolder = GetDriveEntry(toFolderId); + if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); + + var newDriveFolder = GoogleDriveProviderInfo.Storage.InsertEntry(null, driveFolder.Name, toDriveFolder.Id, true); + + GoogleDriveProviderInfo.CacheReset(newDriveFolder); + GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, true); + GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id); + + return ToFolder(newDriveFolder); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var driveFolder = GetDriveEntry(folder.ID); + + if (IsRoot(driveFolder)) + { + //It's root folder + GoogleDriveDaoSelector.RenameProvider(GoogleDriveProviderInfo, newTitle); + //rename provider customer title + } + else + { + //rename folder + driveFolder.Name = newTitle; + driveFolder = GoogleDriveProviderInfo.Storage.RenameEntry(driveFolder.Id, driveFolder.Name); + } + + GoogleDriveProviderInfo.CacheReset(driveFolder); + var parentDriveId = GetParentDriveId(driveFolder); + if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + + return MakeId(driveFolder.Id); + } + + public int GetItemsCount(string folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(string folderId) + { + var driveId = MakeDriveId(folderId); + //note: without cache + return GoogleDriveProviderInfo.Storage.GetEntries(driveId).Count == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return true; + } + + public bool CanCalculateSubitems(string entryId) + { + return false; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var storageMaxUploadSize = GoogleDriveProviderInfo.Storage.GetMaxUploadSize(); + + return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } + + public static class GoogleDriveFolderDaoExtention + { + public static DIHelper AddGoogleDriveFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs new file mode 100644 index 0000000000..ce8a467b9a --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -0,0 +1,377 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Common.Logging; +using ASC.Core.Common.Configuration; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +using DriveFile = Google.Apis.Drive.v3.Data.File; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + [DebuggerDisplay("{CustomerTitle}")] + internal class GoogleDriveProviderInfo : IProviderInfo, IDisposable + { + public OAuth20Token Token { get; set; } + private string _driveRootId; + + internal GoogleDriveStorage Storage + { + get + { + if (Wrapper.Storage == null || !Wrapper.Storage.IsOpened) + { + return Wrapper.CreateStorage(Token, ID); + } + return Wrapper.Storage; + } + } + + internal bool StorageOpened + { + get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; + } + + public int ID { get; set; } + + public Guid Owner { get; private set; } + + public string CustomerTitle { get; private set; } + + public DateTime CreateOn { get; } + + public string RootFolderId + { + get { return "drive-" + ID; } + } + + public string ProviderKey { get; private set; } + + public FolderType RootFolderType { get; } + + public string DriveRootId + { + get + { + if (string.IsNullOrEmpty(_driveRootId)) + { + try + { + _driveRootId = Storage.GetRootFolderId(); + } + catch (Exception ex) + { + Log.Error("GoogleDrive error", ex); + return null; + } + } + return _driveRootId; + } + } + + public GoogleDriveStorageDisposableWrapper Wrapper { get; } + public GoogleDriveProviderInfoHelper GoogleDriveProviderInfoHelper { get; } + public ILog Log { get; } + + public GoogleDriveProviderInfo( + GoogleDriveStorageDisposableWrapper storageDisposableWrapper, + GoogleDriveProviderInfoHelper googleDriveProviderInfoHelper, + IOptionsMonitor options) + { + Wrapper = storageDisposableWrapper; + GoogleDriveProviderInfoHelper = googleDriveProviderInfoHelper; + Log = options.Get("ASC.Files"); + } + + public void Dispose() + { + if (StorageOpened) + Storage.Close(); + } + + public bool CheckAccess() + { + try + { + return !string.IsNullOrEmpty(DriveRootId); + } + catch (UnauthorizedAccessException) + { + return false; + } + } + + public void InvalidateStorage() + { + if (Wrapper != null) + { + Wrapper.Dispose(); + } + + CacheReset(); + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + + internal DriveFile GetDriveEntry(string driveId) + { + return GoogleDriveProviderInfoHelper.GetDriveEntry(Storage, ID, driveId); + } + + internal List GetDriveEntries(string parentDriveId, bool? folder = null) + { + return GoogleDriveProviderInfoHelper.GetDriveEntries(Storage, ID, parentDriveId, folder); + } + + internal void CacheReset(DriveFile driveEntry) + { + GoogleDriveProviderInfoHelper.CacheReset(driveEntry, ID); + } + + internal void CacheReset(string driveId = null, bool? childFolder = null) + { + GoogleDriveProviderInfoHelper.CacheReset(DriveRootId, ID, driveId, childFolder); + } + + internal void CacheResetChilds(string parentDriveId, bool? childFolder = null) + { + GoogleDriveProviderInfoHelper.CacheResetChilds(ID, parentDriveId, childFolder); + } + } + + internal class GoogleDriveStorageDisposableWrapper : IDisposable + { + public GoogleDriveStorage Storage { get; private set; } + public ConsumerFactory ConsumerFactory { get; } + public IServiceProvider ServiceProvider { get; } + + public GoogleDriveStorageDisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider) + { + ConsumerFactory = consumerFactory; + ServiceProvider = serviceProvider; + } + + public GoogleDriveStorage CreateStorage(OAuth20Token _token, int id) + { + if (Storage != null) return Storage; + + var driveStorage = ServiceProvider.GetService(); + + CheckToken(_token, id); + + driveStorage.Open(_token); + return Storage = driveStorage; + } + + private void CheckToken(OAuth20Token _token, int id) + { + if (_token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token"); + if (_token.IsExpired) + { + _token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, _token); + + var dbDao = ServiceProvider.GetService(); + var authData = new AuthData(token: _token.ToJson()); + dbDao.UpdateProviderInfo(id, authData); + } + } + + public void Dispose() + { + Storage?.Close(); + } + } + + public class GoogleDriveProviderInfoHelper + { + private readonly TimeSpan CacheExpiration; + private readonly ICache CacheEntry; + private readonly ICache CacheChildFiles; + private readonly ICache CacheChildFolders; + private readonly ICacheNotify CacheNotify; + + public GoogleDriveProviderInfoHelper(ICacheNotify cacheNotify) + { + CacheExpiration = TimeSpan.FromMinutes(1); + CacheEntry = AscCache.Memory; + CacheChildFiles = AscCache.Memory; + CacheChildFolders = AscCache.Memory; + + CacheNotify = cacheNotify; + CacheNotify.Subscribe((i) => + { + if (i.ResetEntry) + { + CacheEntry.Remove("drive-" + i.Key); + } + if (i.ResetAll) + { + CacheEntry.Remove(new Regex("^drive-" + i.Key + ".*")); + CacheChildFiles.Remove(new Regex("^drivef-" + i.Key + ".*")); + CacheChildFolders.Remove(new Regex("^drived-" + i.Key + ".*")); + } + if (i.ResetChilds) + { + if (!i.ChildFolder || !i.ChildFolder) + { + CacheChildFiles.Remove("drivef-" + i.Key); + } + if (!i.ChildFolderExist || i.ChildFolder) + { + CacheChildFolders.Remove("drived-" + i.Key); + } + } + }, CacheNotifyAction.Remove); + } + + internal DriveFile GetDriveEntry(GoogleDriveStorage storage, int id, string driveId) + { + var entry = CacheEntry.Get("drive-" + id + "-" + driveId); + if (entry == null) + { + entry = storage.GetEntry(driveId); + if (entry != null) + CacheEntry.Insert("drive-" + id + "-" + driveId, entry, DateTime.UtcNow.Add(CacheExpiration)); + } + return entry; + } + + internal List GetDriveEntries(GoogleDriveStorage storage, int id, string parentDriveId, bool? folder = null) + { + if (folder.HasValue) + { + if (folder.Value) + { + var value = CacheChildFolders.Get>("drived-" + id + "-" + parentDriveId); + if (value == null) + { + value = storage.GetEntries(parentDriveId, true); + if (value != null) + CacheChildFolders.Insert("drived-" + id + "-" + parentDriveId, value, DateTime.UtcNow.Add(CacheExpiration)); + } + return value; + } + else + { + var value = CacheChildFiles.Get>("drivef-" + id + "-" + parentDriveId); + if (value == null) + { + value = storage.GetEntries(parentDriveId, false); + if (value != null) + CacheChildFiles.Insert("drivef-" + id + "-" + parentDriveId, value, DateTime.UtcNow.Add(CacheExpiration)); + } + return value; + } + } + + if (CacheChildFiles.Get>("drivef-" + id + "-" + parentDriveId) == null && + CacheChildFolders.Get>("drived-" + id + "-" + parentDriveId) == null) + { + var entries = storage.GetEntries(parentDriveId); + + CacheChildFiles.Insert("drivef-" + id + "-" + parentDriveId, entries.Where(entry => entry.MimeType != GoogleLoginProvider.GoogleDriveMimeTypeFolder).ToList(), DateTime.UtcNow.Add(CacheExpiration)); + CacheChildFolders.Insert("drived-" + id + "-" + parentDriveId, entries.Where(entry => entry.MimeType == GoogleLoginProvider.GoogleDriveMimeTypeFolder).ToList(), DateTime.UtcNow.Add(CacheExpiration)); + + return entries; + } + + var folders = CacheChildFolders.Get>("drived-" + id + "-" + parentDriveId); + if (folders == null) + { + folders = storage.GetEntries(parentDriveId, true); + CacheChildFolders.Insert("drived-" + id + "-" + parentDriveId, folders, DateTime.UtcNow.Add(CacheExpiration)); + } + var files = CacheChildFiles.Get>("drivef-" + id + "-" + parentDriveId); + if (files == null) + { + files = storage.GetEntries(parentDriveId, false); + CacheChildFiles.Insert("drivef-" + id + "-" + parentDriveId, files, DateTime.UtcNow.Add(CacheExpiration)); + } + return folders.Concat(files).ToList(); + } + + internal void CacheReset(DriveFile driveEntry, int id) + { + if (driveEntry != null) + { + CacheNotify.Publish(new GoogleDriveCacheItem { ResetEntry = true, Key = id + "-" + driveEntry.Id }, CacheNotifyAction.Remove); + } + } + + internal void CacheReset(string driveRootId, int id, string driveId = null, bool? childFolder = null) + { + var key = id + "-"; + if (driveId == null) + { + CacheNotify.Publish(new GoogleDriveCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove); + } + else + { + if (driveId == driveRootId) + { + driveId = "root"; + } + key += driveId; + + CacheNotify.Publish(new GoogleDriveCacheItem { ResetEntry = true, ResetChilds = true, Key = key, ChildFolder = childFolder ?? false, ChildFolderExist = childFolder.HasValue }, CacheNotifyAction.Remove); + } + } + + internal void CacheResetChilds(int id, string parentDriveId, bool? childFolder = null) + { + CacheNotify.Publish(new GoogleDriveCacheItem { ResetChilds = true, Key = id + "-" + parentDriveId, ChildFolder = childFolder ?? false, ChildFolderExist = childFolder.HasValue }, CacheNotifyAction.Remove); + } + } + + public static class GoogleDriveProviderInfoExtension + { + public static DIHelper AddGoogleDriveProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddSingleton(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs new file mode 100644 index 0000000000..f5e1d5db87 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs @@ -0,0 +1,100 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Core.Files; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveSecurityDao : GoogleDriveDaoBase, ISecurityDao + { + public GoogleDriveSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + } + + public static class GoogleDriveSecurityDaoExtention + { + public static DIHelper AddGoogleDriveSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs new file mode 100644 index 0000000000..b0a19a33db --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs @@ -0,0 +1,514 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Security; +using System.Text; +using System.Web; + +using ASC.Common.Logging; +using ASC.Core.Common.Configuration; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Web.Core.Files; +using ASC.Web.Files.Core; + +using Google; +using Google.Apis.Auth.OAuth2; +using Google.Apis.Auth.OAuth2.Flows; +using Google.Apis.Auth.OAuth2.Responses; +using Google.Apis.Drive.v3; +using Google.Apis.Services; + +using Microsoft.Extensions.Options; + +using Newtonsoft.Json.Linq; + +using DriveFile = Google.Apis.Drive.v3.Data.File; +using MimeMapping = ASC.Common.Web.MimeMapping; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveStorage + { + public GoogleDriveStorage( + ConsumerFactory consumerFactory, + FileUtility fileUtility, + IOptionsMonitor monitor) + { + ConsumerFactory = consumerFactory; + FileUtility = fileUtility; + Log = monitor.Get("ASC.Files"); + } + + private OAuth20Token _token; + + private string AccessToken + { + get + { + if (_token == null) throw new Exception("Cannot create GoogleDrive session with given token"); + if (_token.IsExpired) _token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, _token); + return _token.AccessToken; + } + } + + private DriveService _driveService; + + public bool IsOpened { get; private set; } + public ConsumerFactory ConsumerFactory { get; } + public FileUtility FileUtility { get; } + public ILog Log { get; } + + public const long MaxChunkedUploadFileSize = 2L * 1024L * 1024L * 1024L; + + public void Open(OAuth20Token token) + { + if (IsOpened) + return; + + if (token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token"); + _token = token; + + var tokenResponse = new TokenResponse + { + AccessToken = _token.AccessToken, + RefreshToken = _token.RefreshToken, + IssuedUtc = _token.Timestamp, + ExpiresInSeconds = _token.ExpiresIn, + TokenType = "Bearer" + }; + + var apiCodeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer + { + ClientSecrets = new ClientSecrets + { + ClientId = _token.ClientID, + ClientSecret = _token.ClientSecret + }, + Scopes = new[] { DriveService.Scope.Drive } + }); + + _driveService = new DriveService(new BaseClientService.Initializer + { + HttpClientInitializer = new UserCredential(apiCodeFlow, string.Empty, tokenResponse) + }); + + IsOpened = true; + } + + public void Close() + { + _driveService.Dispose(); + + IsOpened = false; + } + + + public string GetRootFolderId() + { + var rootFolder = _driveService.Files.Get("root").Execute(); + + return rootFolder.Id; + } + + public DriveFile GetEntry(string entryId) + { + try + { + var request = _driveService.Files.Get(entryId); + + request.Fields = GoogleLoginProvider.FilesFields; + + return request.Execute(); + } + catch (GoogleApiException ex) + { + if (ex.HttpStatusCode == HttpStatusCode.NotFound) + { + return null; + } + throw; + } + } + + public List GetEntries(string folderId, bool? folders = null) + { + var request = _driveService.Files.List(); + + var query = "'" + folderId + "' in parents and trashed=false"; + + if (folders.HasValue) + { + query += " and mimeType " + (folders.Value ? "" : "!") + "= '" + GoogleLoginProvider.GoogleDriveMimeTypeFolder + "'"; + } + + request.Q = query; + + request.Fields = "nextPageToken, files(" + GoogleLoginProvider.FilesFields + ")"; + + var files = new List(); + do + { + try + { + var fileList = request.Execute(); + + files.AddRange(fileList.Files); + + request.PageToken = fileList.NextPageToken; + } + catch (Exception) + { + request.PageToken = null; + } + } while (!string.IsNullOrEmpty(request.PageToken)); + + return files; + } + + public Stream DownloadStream(DriveFile file, int offset = 0) + { + if (file == null) throw new ArgumentNullException("file"); + + var downloadArg = string.Format("{0}?alt=media", file.Id); + + var ext = MimeMapping.GetExtention(file.MimeType); + if (GoogleLoginProvider.GoogleDriveExt.Contains(ext)) + { + var internalExt = FileUtility.GetGoogleDownloadableExtension(ext); + var requiredMimeType = MimeMapping.GetMimeMapping(internalExt); + + downloadArg = string.Format("{0}/export?mimeType={1}", + file.Id, + HttpUtility.UrlEncode(requiredMimeType)); + } + + var request = WebRequest.Create(GoogleLoginProvider.GoogleUrlFile + downloadArg); + request.Method = "GET"; + request.Headers.Add("Authorization", "Bearer " + AccessToken); + + var response = (HttpWebResponse)request.GetResponse(); + + if (offset == 0 && file.Size.HasValue && file.Size > 0) + { + return new ResponseStream(response.GetResponseStream(), file.Size.Value); + } + + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + using (var str = response.GetResponseStream()) + { + if (str != null) + { + str.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(offset, SeekOrigin.Begin); + } + } + + return tempBuffer; + } + + public DriveFile InsertEntry(Stream fileStream, string title, string parentId, bool folder = false) + { + var mimeType = folder ? GoogleLoginProvider.GoogleDriveMimeTypeFolder : MimeMapping.GetMimeMapping(title); + + var body = FileConstructor(title, mimeType, parentId); + + if (folder) + { + var requestFolder = _driveService.Files.Create(body); + requestFolder.Fields = GoogleLoginProvider.FilesFields; + return requestFolder.Execute(); + } + + var request = _driveService.Files.Create(body, fileStream, mimeType); + request.Fields = GoogleLoginProvider.FilesFields; + + var result = request.Upload(); + if (result.Exception != null) + { + if (request.ResponseBody == null) throw result.Exception; + Log.Error("Error while trying to insert entity. GoogleDrive insert returned an error.", result.Exception); + } + return request.ResponseBody; + } + + public void DeleteEntry(string entryId) + { + _driveService.Files.Delete(entryId).Execute(); + } + + public DriveFile InsertEntryIntoFolder(DriveFile entry, string folderId) + { + var request = _driveService.Files.Update(FileConstructor(), entry.Id); + request.AddParents = folderId; + request.Fields = GoogleLoginProvider.FilesFields; + return request.Execute(); + } + + public DriveFile RemoveEntryFromFolder(DriveFile entry, string folderId) + { + var request = _driveService.Files.Update(FileConstructor(), entry.Id); + request.RemoveParents = folderId; + request.Fields = GoogleLoginProvider.FilesFields; + return request.Execute(); + } + + public DriveFile CopyEntry(string toFolderId, string originEntryId) + { + var body = FileConstructor(folderId: toFolderId); + try + { + var request = _driveService.Files.Copy(body, originEntryId); + request.Fields = GoogleLoginProvider.FilesFields; + return request.Execute(); + } + catch (GoogleApiException ex) + { + if (ex.HttpStatusCode == HttpStatusCode.Forbidden) + { + throw new SecurityException(ex.Error.Message); + } + throw; + } + } + + public DriveFile RenameEntry(string fileId, string newTitle) + { + var request = _driveService.Files.Update(FileConstructor(newTitle), fileId); + request.Fields = GoogleLoginProvider.FilesFields; + return request.Execute(); + } + + public DriveFile SaveStream(string fileId, Stream fileStream, string fileTitle) + { + var mimeType = MimeMapping.GetMimeMapping(fileTitle); + var file = FileConstructor(fileTitle, mimeType); + + var request = _driveService.Files.Update(file, fileId, fileStream, mimeType); + request.Fields = GoogleLoginProvider.FilesFields; + var result = request.Upload(); + if (result.Exception != null) + { + if (request.ResponseBody == null) throw result.Exception; + Log.Error("Error while trying to insert entity. GoogleDrive save returned an error.", result.Exception); + } + + return request.ResponseBody; + } + + public DriveFile FileConstructor(string title = null, string mimeType = null, string folderId = null) + { + var file = new DriveFile(); + + if (!string.IsNullOrEmpty(title)) file.Name = title; + if (!string.IsNullOrEmpty(mimeType)) file.MimeType = mimeType; + if (!string.IsNullOrEmpty(folderId)) file.Parents = new List { folderId }; + + return file; + } + + public ResumableUploadSession CreateResumableSession(DriveFile driveFile, long contentLength) + { + if (driveFile == null) throw new ArgumentNullException("driveFile"); + + var fileId = string.Empty; + var method = "POST"; + var body = string.Empty; + var folderId = driveFile.Parents.FirstOrDefault(); + + if (driveFile.Id != null) + { + fileId = "/" + driveFile.Id; + method = "PATCH"; + } + else + { + var titleData = !string.IsNullOrEmpty(driveFile.Name) ? string.Format("\"name\":\"{0}\"", driveFile.Name) : ""; + var parentData = !string.IsNullOrEmpty(folderId) ? string.Format(",\"parents\":[\"{0}\"]", folderId) : ""; + + body = !string.IsNullOrEmpty(titleData + parentData) ? string.Format("{{{0}{1}}}", titleData, parentData) : ""; + } + + var request = WebRequest.Create(GoogleLoginProvider.GoogleUrlFileUpload + fileId + "?uploadType=resumable"); + request.Method = method; + + var bytes = Encoding.UTF8.GetBytes(body); + request.ContentLength = bytes.Length; + request.ContentType = "application/json; charset=UTF-8"; + request.Headers.Add("X-Upload-Content-Type", MimeMapping.GetMimeMapping(driveFile.Name)); + request.Headers.Add("X-Upload-Content-Length", contentLength.ToString(CultureInfo.InvariantCulture)); + request.Headers.Add("Authorization", "Bearer " + AccessToken); + + request.GetRequestStream().Write(bytes, 0, bytes.Length); + + var uploadSession = new ResumableUploadSession(driveFile.Id, folderId, contentLength); + using (var response = request.GetResponse()) + { + uploadSession.Location = response.Headers["Location"]; + } + uploadSession.Status = ResumableUploadSessionStatus.Started; + + return uploadSession; + } + + public void Transfer(ResumableUploadSession googleDriveSession, Stream stream, long chunkLength) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (googleDriveSession.Status != ResumableUploadSessionStatus.Started) + throw new InvalidOperationException("Can't upload chunk for given upload session."); + + var request = WebRequest.Create(googleDriveSession.Location); + request.Method = "PUT"; + request.ContentLength = chunkLength; + request.Headers.Add("Authorization", "Bearer " + AccessToken); + request.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", + googleDriveSession.BytesTransfered, + googleDriveSession.BytesTransfered + chunkLength - 1, + googleDriveSession.BytesToTransfer)); + + using (var requestStream = request.GetRequestStream()) + { + stream.CopyTo(requestStream); + } + + HttpWebResponse response; + try + { + response = (HttpWebResponse)request.GetResponse(); + } + catch (WebException exception) + { + if (exception.Status == WebExceptionStatus.ProtocolError) + { + if (exception.Response != null && exception.Response.Headers.AllKeys.Contains("Range")) + { + response = (HttpWebResponse)exception.Response; + } + else if (exception.Message.Equals("Invalid status code: 308", StringComparison.InvariantCulture)) //response is null (unix) + { + response = null; + } + else + { + throw; + } + } + else + { + throw; + } + } + + if (response == null || response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.OK) + { + var uplSession = googleDriveSession; + uplSession.BytesTransfered += chunkLength; + + if (response != null) + { + var locationHeader = response.Headers["Location"]; + if (!string.IsNullOrEmpty(locationHeader)) + { + uplSession.Location = locationHeader; + } + } + } + else + { + googleDriveSession.Status = ResumableUploadSessionStatus.Completed; + + using (var responseStream = response.GetResponseStream()) + { + if (responseStream == null) return; + string responseString; + using (var readStream = new StreamReader(responseStream)) + { + responseString = readStream.ReadToEnd(); + } + var responseJson = JObject.Parse(responseString); + + googleDriveSession.FileId = responseJson.Value("id"); + } + } + + if (response != null) + { + response.Close(); + } + } + + public long GetMaxUploadSize() + { + var request = _driveService.About.Get(); + request.Fields = "maxUploadSize"; + var about = request.Execute(); + + return about.MaxUploadSize.HasValue ? about.MaxUploadSize.Value : MaxChunkedUploadFileSize; + } + } + + public enum ResumableUploadSessionStatus + { + None, + Started, + Completed, + Aborted + } + + [Serializable] + internal class ResumableUploadSession + { + public long BytesToTransfer { get; set; } + + public long BytesTransfered { get; set; } + + public string FileId { get; set; } + + public string FolderId { get; set; } + + public ResumableUploadSessionStatus Status { get; set; } + + public string Location { get; set; } + + public ResumableUploadSession(string fileId, string folderId, long bytesToTransfer) + { + FileId = fileId; + FolderId = folderId; + BytesToTransfer = bytesToTransfer; + Status = ResumableUploadSessionStatus.None; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs new file mode 100644 index 0000000000..90ba9d40e2 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs @@ -0,0 +1,177 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Core.Files; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.GoogleDrive +{ + internal class GoogleDriveTagDao : GoogleDriveDaoBase, ITagDao + { + public GoogleDriveTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + { + } + #region ITagDao Members + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + var folderId = GoogleDriveDaoSelector.ConvertId(parentFolder.ID); + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(GetChildren(folderId)); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return null; + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return null; + } + + public IEnumerable SaveTags(Tag tag) + { + return null; + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return null; + } + + public void MarkAsNew(Guid subject, FileEntry fileEntry) + { + } + + #endregion + } + + public static class GoogleDriveTagDaoExtention + { + public static DIHelper AddGoogleDriveTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index 12b2e6407a..5d5ca7da44 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -42,6 +42,7 @@ using ASC.Files.Core.EF; using ASC.Files.Resources; using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; +using ASC.Files.Thirdparty.GoogleDrive; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; @@ -570,6 +571,7 @@ namespace ASC.Files.Thirdparty //services.TryAddScoped(); return services + .AddGoogleDriveProviderInfoService() .AddBoxProviderInfoService() .AddDropboxProviderInfoService() .AddTenantUtilService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index a1a431c7d9..bcb8546a8b 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -35,6 +35,7 @@ using ASC.Files.Core.Data; using ASC.Files.Resources; using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; +using ASC.Files.Thirdparty.GoogleDrive; using ASC.Web.Files.Utils; using ASC.Web.Studio.Core; @@ -62,10 +63,9 @@ namespace ASC.Files.Thirdparty.ProviderDao { //Fill in selectors - //Selectors.Add(Default); //Legacy DB dao //Selectors.Add(new SharpBoxDaoSelector()); //Selectors.Add(new SharePointDaoSelector()); - //Selectors.Add(new GoogleDriveDaoSelector()); + ServiceProvider.GetService(), ServiceProvider.GetService(), ServiceProvider.GetService() }; @@ -265,6 +265,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderDaoBaseService(this DIHelper services) { return services + .AddGoogleDriveSelectorService() .AddDropboxDaoSelectorService() .AddBoxDaoSelectorService(); } diff --git a/products/ASC.Files/Server/proto/GoogleDriveCacheItem.proto b/products/ASC.Files/Server/proto/GoogleDriveCacheItem.proto new file mode 100644 index 0000000000..704fb441c7 --- /dev/null +++ b/products/ASC.Files/Server/proto/GoogleDriveCacheItem.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty.GoogleDrive; + +message GoogleDriveCacheItem { + bool ResetAll = 1; + bool ResetEntry = 2; + bool ResetChilds = 3; + string Key = 4; + bool ChildFolder = 5; + bool ChildFolderExist = 6; +} \ No newline at end of file From 2241198a81ccbcd034d70dd60e9864a3a2160ea8 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 13 Mar 2020 10:37:42 +0300 Subject: [PATCH 12/30] Files: Thirdparty. Onedrive, sharepoint --- products/ASC.Files/Server/ASC.Files.csproj | 6 + .../Server/Core/Dao/TeamlabDao/FileDao.cs | 12 +- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 4 +- .../Server/Core/FileStorageService.cs | 2 +- .../GoogleDrive/GoogleDriveDaoBase.cs | 2 - .../GoogleDrive/GoogleDriveProviderInfo.cs | 27 +- .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 394 ++++++++++ .../OneDrive/OneDriveDaoSelector.cs | 178 +++++ .../Thirdparty/OneDrive/OneDriveFileDao.cs | 605 ++++++++++++++++ .../Thirdparty/OneDrive/OneDriveFolderDao.cs | 425 +++++++++++ .../OneDrive/OneDriveProviderInfo.cs | 266 +++++++ .../OneDrive/OneDriveSecurityDao.cs | 106 +++ .../Thirdparty/OneDrive/OneDriveStorage.cs | 392 ++++++++++ .../Thirdparty/OneDrive/OneDriveTagDao.cs | 182 +++++ .../Core/Thirdparty/ProviderAccountDao.cs | 84 ++- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 10 +- .../SharePoint/SharePointDaoBase.cs | 210 ++++++ .../SharePoint/SharePointDaoSelector.cs | 163 +++++ .../SharePoint/SharePointErrorEntry.cs | 54 ++ .../SharePoint/SharePointFileDao.cs | 431 +++++++++++ .../SharePoint/SharePointFolderDao.cs | 379 ++++++++++ .../SharePoint/SharePointProviderInfo.cs | 677 ++++++++++++++++++ .../SharePoint/SharePointSecurityDao.cs | 104 +++ .../Thirdparty/SharePoint/SharePointTagDao.cs | 176 +++++ products/ASC.Files/Server/Utils/FileMarker.cs | 2 +- .../Server/proto/OneDriveCacheItem.proto | 8 + .../proto/SharePointProviderCacheItem.proto | 8 + 27 files changed, 4844 insertions(+), 63 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveStorage.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointErrorEntry.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs create mode 100644 products/ASC.Files/Server/proto/OneDriveCacheItem.proto create mode 100644 products/ASC.Files/Server/proto/SharePointProviderCacheItem.proto diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index 4fa6e7c371..524082b811 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -22,7 +22,9 @@ + + @@ -35,6 +37,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + @@ -48,6 +52,8 @@ + + diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index 20dfe2b797..01a5718364 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -397,7 +397,7 @@ namespace ASC.Files.Core.Data Version = file.Version, VersionGroup = file.VersionGroup, CurrentVersion = true, - FolderId = (int)file.FolderID, + FolderId = file.FolderID, Title = file.Title, ContentLength = file.ContentLength, Category = (int)file.FilterType, @@ -421,7 +421,7 @@ namespace ASC.Files.Core.Data parentFoldersIds = FilesDbContext.Tree - .Where(r => r.FolderId == (int)file.FolderID) + .Where(r => r.FolderId == file.FolderID) .OrderByDescending(r => r.Level) .Select(r => r.ParentId) .ToList(); @@ -513,7 +513,7 @@ namespace ASC.Files.Core.Data toUpdate.Version = file.Version; toUpdate.VersionGroup = file.VersionGroup; - toUpdate.FolderId = (int)file.FolderID; + toUpdate.FolderId = file.FolderID; toUpdate.Title = file.Title; toUpdate.ContentLength = file.ContentLength; toUpdate.Category = (int)file.FilterType; @@ -533,7 +533,7 @@ namespace ASC.Files.Core.Data file.PureTitle = file.Title; parentFoldersIds = FilesDbContext.Tree - .Where(r => r.FolderId == (int)file.FolderID) + .Where(r => r.FolderId == file.FolderID) .OrderByDescending(r => r.Level) .Select(r => r.ParentId) .ToList(); @@ -649,7 +649,7 @@ namespace ASC.Files.Core.Data DeleteFolder(fileId); var wrapper = ServiceProvider.GetService(); - wrapper.Id = (int)fileId; + wrapper.Id = fileId; FactoryIndexer.DeleteAsync(wrapper); } @@ -703,7 +703,7 @@ namespace ASC.Files.Core.Data var parentFoldersIds = FilesDbContext.Tree - .Where(r => r.FolderId == (int)toFolderId) + .Where(r => r.FolderId == toFolderId) .OrderByDescending(r => r.Level) .Select(r => r.ParentId) .ToList(); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index 83bc453d54..778f0aec2e 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -425,7 +425,7 @@ namespace ASC.Files.Core.Data RecalculateFoldersCount(parent); } - FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = (int)id }); + FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = id }); } public int MoveFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) @@ -733,7 +733,7 @@ namespace ASC.Files.Core.Data break; default: folder.FolderType = FolderType.BUNCH; - folder.Title = (string)key; + folder.Title = key; break; } using var tx = FilesDbContext.Database.BeginTransaction();//NOTE: Maybe we shouldn't start transaction here at all diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 6c40e12dcc..9da5437918 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -1832,7 +1832,7 @@ namespace ASC.Web.Files.Services.WCFService var folderAccess = folder.Access; newFolder.CreateBy = userInfo.ID; - var newFolderID = folderDao.SaveFolder((Folder)newFolder); + var newFolderID = folderDao.SaveFolder(newFolder); newFolder = folderDao.GetFolder(newFolderID); newFolder.Access = folderAccess; diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs index 64e9d69479..a6ff8f463f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs @@ -59,7 +59,6 @@ namespace ASC.Files.Thirdparty.GoogleDrive public string PathPrefix { get; set; } public IServiceProvider ServiceProvider { get; } public UserManager UserManager { get; } - public TenantManager TenantManager { get; } public TenantUtil TenantUtil { get; } public FilesDbContext FilesDbContext { get; } public SetupInfo SetupInfo { get; } @@ -76,7 +75,6 @@ namespace ASC.Files.Thirdparty.GoogleDrive { ServiceProvider = serviceProvider; UserManager = userManager; - TenantManager = tenantManager; TenantUtil = tenantUtil; TenantID = tenantManager.GetCurrentTenant().TenantId; FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index ce8a467b9a..61d0bc69fd 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -71,20 +71,20 @@ namespace ASC.Files.Thirdparty.GoogleDrive public int ID { get; set; } - public Guid Owner { get; private set; } + public Guid Owner { get; set; } - public string CustomerTitle { get; private set; } + public string CustomerTitle { get; set; } - public DateTime CreateOn { get; } + public DateTime CreateOn { get; set; } public string RootFolderId { get { return "drive-" + ID; } } - public string ProviderKey { get; private set; } + public string ProviderKey { get; set; } - public FolderType RootFolderType { get; } + public FolderType RootFolderType { get; set; } public string DriveRootId { @@ -191,27 +191,27 @@ namespace ASC.Files.Thirdparty.GoogleDrive ServiceProvider = serviceProvider; } - public GoogleDriveStorage CreateStorage(OAuth20Token _token, int id) + public GoogleDriveStorage CreateStorage(OAuth20Token token, int id) { if (Storage != null) return Storage; var driveStorage = ServiceProvider.GetService(); - CheckToken(_token, id); + CheckToken(token, id); - driveStorage.Open(_token); + driveStorage.Open(token); return Storage = driveStorage; } - private void CheckToken(OAuth20Token _token, int id) + private void CheckToken(OAuth20Token token, int id) { - if (_token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token"); - if (_token.IsExpired) + if (token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token"); + if (token.IsExpired) { - _token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, _token); + token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, token); var dbDao = ServiceProvider.GetService(); - var authData = new AuthData(token: _token.ToJson()); + var authData = new AuthData(token: token.ToJson()); dbDao.UpdateProviderInfo(id, authData); } } @@ -369,6 +369,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive { services.TryAddScoped(); services.TryAddScoped(); + services.TryAddScoped(); services.TryAddSingleton(); return services; diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs new file mode 100644 index 0000000000..555df1aa03 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -0,0 +1,394 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Security.Cryptography; +using ASC.Web.Files.Classes; +using ASC.Web.Studio.Core; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OneDrive.Sdk; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal abstract class OneDriveDaoBase + { + public OneDriveDaoSelector OneDriveDaoSelector { get; set; } + + public int TenantID { get; private set; } + public OneDriveProviderInfo OneDriveProviderInfo { get; set; } + public string PathPrefix { get; set; } + public TenantUtil TenantUtil { get; } + public FilesDbContext FilesDbContext { get; } + public SetupInfo SetupInfo { get; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + + public OneDriveDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + { + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + SetupInfo = setupInfo; + } + + public void Init(OneDriveDaoSelector.OneDriveInfo onedriveInfo, OneDriveDaoSelector onedriveDaoSelector) + { + OneDriveProviderInfo = onedriveInfo.OneDriveProviderInfo; + PathPrefix = onedriveInfo.PathPrefix; + OneDriveDaoSelector = onedriveDaoSelector; + } + + public void Dispose() + { + OneDriveProviderInfo.Dispose(); + } + + protected string MappingID(string id, bool saveIfNotExist = false) + { + if (id == null) return null; + + string result; + if (id.ToString().StartsWith("onedrive")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + return result; + } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + + protected static string MakeOneDriveId(string entryId) + { + var id = entryId; + return string.IsNullOrEmpty(id) + ? string.Empty + : id.TrimStart('/'); + } + + protected static string GetParentFolderId(Item onedriveItem) + { + return onedriveItem == null || IsRoot(onedriveItem) + ? null + : (onedriveItem.ParentReference.Path.Equals(OneDriveStorage.RootPath, StringComparison.InvariantCultureIgnoreCase) + ? string.Empty + : onedriveItem.ParentReference.Id); + } + + protected string MakeId(Item onedriveItem) + { + var id = string.Empty; + if (onedriveItem != null) + { + id = onedriveItem.Id; + } + + return MakeId(id); + } + + protected string MakeId(string id = null) + { + return string.Format("{0}{1}", PathPrefix, + string.IsNullOrEmpty(id) || id == "" + ? "" : ("-|" + id.TrimStart('/'))); + } + + public string MakeOneDrivePath(Item onedriveItem) + { + return onedriveItem == null || IsRoot(onedriveItem) + ? string.Empty + : (OneDriveStorage.MakeOneDrivePath( + new Regex("^" + OneDriveStorage.RootPath).Replace(onedriveItem.ParentReference.Path, ""), + onedriveItem.Name)); + } + + protected string MakeItemTitle(Item onedriveItem) + { + if (onedriveItem == null || IsRoot(onedriveItem)) + { + return OneDriveProviderInfo.CustomerTitle; + } + + return Global.ReplaceInvalidCharsAndTruncate(onedriveItem.Name); + } + + protected Folder ToFolder(Item onedriveFolder) + { + if (onedriveFolder == null) return null; + if (onedriveFolder is ErrorItem) + { + //Return error entry + return ToErrorFolder(onedriveFolder as ErrorItem); + } + + if (onedriveFolder.Folder == null) return null; + + var isRoot = IsRoot(onedriveFolder); + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(isRoot ? string.Empty : onedriveFolder.Id); + folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(onedriveFolder)); + folder.CreateBy = OneDriveProviderInfo.Owner; + folder.CreateOn = isRoot ? OneDriveProviderInfo.CreateOn : (onedriveFolder.CreatedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.CreatedDateTime.Value.DateTime) : default(DateTime)); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = OneDriveProviderInfo.Owner; + folder.ModifiedOn = isRoot ? OneDriveProviderInfo.CreateOn : (onedriveFolder.LastModifiedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.LastModifiedDateTime.Value.DateTime) : default(DateTime)); + folder.ProviderId = OneDriveProviderInfo.ID; + folder.ProviderKey = OneDriveProviderInfo.ProviderKey; + folder.RootFolderCreator = OneDriveProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = OneDriveProviderInfo.RootFolderType; + + folder.Shareable = false; + folder.Title = MakeItemTitle(onedriveFolder); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + + return folder; + } + + protected static bool IsRoot(Item onedriveFolder) + { + return onedriveFolder.ParentReference == null || onedriveFolder.ParentReference.Id == null; + } + + private File ToErrorFile(ErrorItem onedriveFile) + { + if (onedriveFile == null) return null; + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(onedriveFile.ErrorId); + file.CreateBy = OneDriveProviderInfo.Owner; + file.CreateOn = TenantUtil.DateTimeNow(); + file.ModifiedBy = OneDriveProviderInfo.Owner; + file.ModifiedOn = TenantUtil.DateTimeNow(); + file.ProviderId = OneDriveProviderInfo.ID; + file.ProviderKey = OneDriveProviderInfo.ProviderKey; + file.RootFolderCreator = OneDriveProviderInfo.Owner; + file.RootFolderId = MakeId(); + file.RootFolderType = OneDriveProviderInfo.RootFolderType; + file.Title = MakeItemTitle(onedriveFile); + file.Error = onedriveFile.Error; + + return file; + } + + private Folder ToErrorFolder(ErrorItem onedriveFolder) + { + if (onedriveFolder == null) return null; + + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(onedriveFolder.ErrorId); + folder.ParentFolderID = null; + folder.CreateBy = OneDriveProviderInfo.Owner; + folder.CreateOn = TenantUtil.DateTimeNow(); + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = OneDriveProviderInfo.Owner; + folder.ModifiedOn = TenantUtil.DateTimeNow(); + folder.ProviderId = OneDriveProviderInfo.ID; + folder.ProviderKey = OneDriveProviderInfo.ProviderKey; + folder.RootFolderCreator = OneDriveProviderInfo.Owner; + folder.RootFolderId = MakeId(); + folder.RootFolderType = OneDriveProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeItemTitle(onedriveFolder); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + folder.Error = onedriveFolder.Error; + return folder; + } + + public File ToFile(Item onedriveFile) + { + if (onedriveFile == null) return null; + + if (onedriveFile is ErrorItem) + { + //Return error entry + return ToErrorFile(onedriveFile as ErrorItem); + } + + if (onedriveFile.File == null) return null; + + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(onedriveFile.Id); + file.Access = FileShare.None; + file.ContentLength = onedriveFile.Size.HasValue ? (long)onedriveFile.Size : 0; + file.CreateBy = OneDriveProviderInfo.Owner; + file.CreateOn = onedriveFile.CreatedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFile.CreatedDateTime.Value.DateTime) : default; + file.FileStatus = FileStatus.None; + file.FolderID = MakeId(GetParentFolderId(onedriveFile)); + file.ModifiedBy = OneDriveProviderInfo.Owner; + file.ModifiedOn = onedriveFile.LastModifiedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFile.LastModifiedDateTime.Value.DateTime) : default; + file.NativeAccessor = onedriveFile; + file.ProviderId = OneDriveProviderInfo.ID; + file.ProviderKey = OneDriveProviderInfo.ProviderKey; + file.Title = MakeItemTitle(onedriveFile); + file.RootFolderId = MakeId(); + file.RootFolderType = OneDriveProviderInfo.RootFolderType; + file.RootFolderCreator = OneDriveProviderInfo.Owner; + file.Shared = false; + file.Version = 1; + + return file; + } + + public Folder GetRootFolder(string folderId) + { + return ToFolder(GetOneDriveItem("")); + } + + protected Item GetOneDriveItem(string itemId) + { + var onedriveId = MakeOneDriveId(itemId); + try + { + return OneDriveProviderInfo.GetOneDriveItem(onedriveId); + } + catch (Exception ex) + { + return new ErrorItem(ex, onedriveId); + } + } + + protected IEnumerable GetChildren(string folderId) + { + return GetOneDriveItems(folderId).Select(entry => MakeId(entry.Id)); + } + + protected List GetOneDriveItems(string parentId, bool? folder = null) + { + var onedriveFolderId = MakeOneDriveId(parentId); + var items = OneDriveProviderInfo.GetOneDriveItems(onedriveFolderId); + + if (folder.HasValue) + { + if (folder.Value) + { + return items.Where(i => i.Folder != null).ToList(); + } + + return items.Where(i => i.File != null).ToList(); + } + + return items; + } + + protected sealed class ErrorItem : Item + { + public string Error { get; set; } + + public string ErrorId { get; private set; } + + + public ErrorItem(Exception e, object id) + { + ErrorId = id.ToString(); + if (e != null) + { + Error = e.Message; + } + } + } + + protected string GetAvailableTitle(string requestTitle, string parentFolderId, Func isExist) + { + requestTitle = new Regex("\\.$").Replace(requestTitle, "_"); + if (!isExist(requestTitle, parentFolderId)) return requestTitle; + + var re = new Regex(@"( \(((?[0-9])+)\)(\.[^\.]*)?)$"); + var match = re.Match(requestTitle); + + if (!match.Success) + { + var insertIndex = requestTitle.Length; + if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1) + { + insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture); + } + requestTitle = requestTitle.Insert(insertIndex, " (1)"); + } + + while (isExist(requestTitle, parentFolderId)) + { + requestTitle = re.Replace(requestTitle, MatchEvaluator); + } + return requestTitle; + } + + private static string MatchEvaluator(Match match) + { + var index = Convert.ToInt32(match.Groups[2].Value); + var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); + return string.Format(" ({0}){1}", index + 1, staticText); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs new file mode 100644 index 0000000000..f6d470a6ff --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs @@ -0,0 +1,178 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveDaoSelector : RegexDaoSelectorBase + { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } + + internal class OneDriveInfo + { + public OneDriveProviderInfo OneDriveProviderInfo { get; set; } + + public string Path { get; set; } + public string PathPrefix { get; set; } + } + + public OneDriveDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) + : base(new Regex(@"^onedrive-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override IFolderDao GetFolderDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ITagDao GetTagDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ISecurityDao GetSecurityDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a OneDrive id"); + } + return base.ConvertId(null); + } + + private OneDriveInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new OneDriveInfo + { + Path = match.Groups["path"].Value, + OneDriveProviderInfo = providerInfo, + PathPrefix = "onedrive-" + match.Groups["id"].Value + }; + } + throw new ArgumentException("Id is not a OneDrive id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private OneDriveProviderInfo GetProviderInfo(int linkId) + { + OneDriveProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + + try + { + info = (OneDriveProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(OneDriveProviderInfo onedriveProviderInfo, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(onedriveProviderInfo.ID, newTitle, null, onedriveProviderInfo.RootFolderType); + onedriveProviderInfo.UpdateTitle(newTitle); //This will update cached version too + } + } + + public static class OneDriveDaoSelectorExtention + { + public static DIHelper AddOneDriveSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddOneDriveSecurityDaoService() + .AddOneDriveTagDaoService() + .AddOneDriveFolderDaoService() + .AddOneDriveFileDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs new file mode 100644 index 0000000000..f690a91150 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -0,0 +1,605 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +using Microsoft.OneDrive.Sdk; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveFileDao : OneDriveDaoBase, IFileDao + { + public OneDriveFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void InvalidateCache(string fileId) + { + var onedriveFileId = MakeOneDriveId(fileId); + OneDriveProviderInfo.CacheReset(onedriveFileId); + + var onedriveFile = GetOneDriveItem(fileId); + var parentId = GetParentFolderId(onedriveFile); + if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ToFile(GetOneDriveItem(fileId)); + } + + public File GetFile(string parentId, string title) + { + return ToFile(GetOneDriveItems(parentId, false) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase) && item.File != null)); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ToFile(GetOneDriveItem(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + if (fileIds == null || fileIds.Length == 0) return new List>(); + return fileIds.Select(GetOneDriveItem).Select(ToFile).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + return GetOneDriveItems(parentId, false).Select(entry => MakeId(entry.Id)).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = GetOneDriveItems(parentId, false).Select(ToFile); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public Stream GetFileStream(File file, long offset) + { + var onedriveFileId = MakeOneDriveId(file.ID); + OneDriveProviderInfo.CacheReset(onedriveFileId); + + var onedriveFile = GetOneDriveItem(file.ID); + if (onedriveFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + if (onedriveFile is ErrorItem) throw new Exception(((ErrorItem)onedriveFile).Error); + + var fileStream = OneDriveProviderInfo.Storage.DownloadStream(onedriveFile, (int)offset); + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public File SaveFile(File file, Stream fileStream) + { + if (file == null) throw new ArgumentNullException("file"); + if (fileStream == null) throw new ArgumentNullException("fileStream"); + + Item newOneDriveFile = null; + + if (file.ID != null) + { + newOneDriveFile = OneDriveProviderInfo.Storage.SaveStream(MakeOneDriveId(file.ID), fileStream); + if (!newOneDriveFile.Name.Equals(file.Title)) + { + file.Title = GetAvailableTitle(file.Title, GetParentFolderId(newOneDriveFile), IsExist); + newOneDriveFile = OneDriveProviderInfo.Storage.RenameItem(newOneDriveFile.Id, file.Title); + } + } + else if (file.FolderID != null) + { + var folderId = MakeOneDriveId(file.FolderID); + var folder = GetOneDriveItem(folderId); + file.Title = GetAvailableTitle(file.Title, folderId, IsExist); + newOneDriveFile = OneDriveProviderInfo.Storage.CreateFile(fileStream, file.Title, MakeOneDrivePath(folder)); + } + + if (newOneDriveFile != null) OneDriveProviderInfo.CacheReset(newOneDriveFile.Id); + var parentId = GetParentFolderId(newOneDriveFile); + if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + + return ToFile(newOneDriveFile); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var onedriveFile = GetOneDriveItem(fileId); + if (onedriveFile == null) return; + var id = MakeId(onedriveFile.Id); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(onedriveFile is ErrorItem)) + OneDriveProviderInfo.Storage.DeleteItem(onedriveFile); + + OneDriveProviderInfo.CacheReset(onedriveFile.Id); + var parentFolderId = GetParentFolderId(onedriveFile); + if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + } + + public bool IsExist(string title, object folderId) + { + return GetOneDriveItems(folderId.ToString(), false) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public string MoveFile(string fileId, string toFolderId) + { + var onedriveFile = GetOneDriveItem(fileId); + if (onedriveFile is ErrorItem) throw new Exception(((ErrorItem)onedriveFile).Error); + + var toOneDriveFolder = GetOneDriveItem(toFolderId); + if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); + + var fromFolderId = GetParentFolderId(onedriveFile); + + var newTitle = GetAvailableTitle(onedriveFile.Name, toOneDriveFolder.Id, IsExist); + onedriveFile = OneDriveProviderInfo.Storage.MoveItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); + + OneDriveProviderInfo.CacheReset(onedriveFile.Id); + OneDriveProviderInfo.CacheReset(fromFolderId); + OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + + return MakeId(onedriveFile.Id); + } + + public File CopyFile(string fileId, string toFolderId) + { + var onedriveFile = GetOneDriveItem(fileId); + if (onedriveFile is ErrorItem) throw new Exception(((ErrorItem)onedriveFile).Error); + + var toOneDriveFolder = GetOneDriveItem(toFolderId); + if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); + + var newTitle = GetAvailableTitle(onedriveFile.Name, toOneDriveFolder.Id, IsExist); + var newOneDriveFile = OneDriveProviderInfo.Storage.CopyItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); + + OneDriveProviderInfo.CacheReset(newOneDriveFile.Id); + OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + + return ToFile(newOneDriveFile); + } + + public string FileRename(File file, string newTitle) + { + var onedriveFile = GetOneDriveItem(file.ID); + newTitle = GetAvailableTitle(newTitle, GetParentFolderId(onedriveFile), IsExist); + + onedriveFile = OneDriveProviderInfo.Storage.RenameItem(onedriveFile.Id, newTitle); + + OneDriveProviderInfo.CacheReset(onedriveFile.Id); + var parentId = GetParentFolderId(onedriveFile); + if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + + return MakeId(onedriveFile.Id); + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + #region chunking + + private File RestoreIds(File file) + { + if (file == null) return null; + + if (file.ID != null) + file.ID = MakeId(file.ID.ToString()); + + if (file.FolderID != null) + file.FolderID = MakeId(file.FolderID.ToString()); + + return file; + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + if (SetupInfo.ChunkUploadSize > contentLength) + return new ChunkedUploadSession(RestoreIds(file), contentLength) { UseChunks = false }; + + var uploadSession = new ChunkedUploadSession(file, contentLength); + + Item onedriveFile; + if (file.ID != null) + { + onedriveFile = GetOneDriveItem(file.ID); + } + else + { + var folder = GetOneDriveItem(file.FolderID); + onedriveFile = new Item { Name = file.Title, ParentReference = new ItemReference { Id = folder.Id } }; + } + + var onedriveSession = OneDriveProviderInfo.Storage.CreateResumableSession(onedriveFile, contentLength); + if (onedriveSession != null) + { + uploadSession.Items["OneDriveSession"] = onedriveSession; + } + else + { + uploadSession.Items["TempPath"] = Path.GetTempFileName(); + } + + uploadSession.File = RestoreIds(uploadSession.File); + return uploadSession; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, stream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + if (uploadSession.Items.ContainsKey("OneDriveSession")) + { + var oneDriveSession = uploadSession.GetItemOrDefault("OneDriveSession"); + OneDriveProviderInfo.Storage.Transfer(oneDriveSession, stream, chunkLength); + } + else + { + var tempPath = uploadSession.GetItemOrDefault("TempPath"); + using (var fs = new FileStream(tempPath, FileMode.Append)) + { + stream.CopyTo(fs); + } + } + + uploadSession.BytesUploaded += chunkLength; + + if (uploadSession.BytesUploaded == uploadSession.BytesTotal) + { + uploadSession.File = FinalizeUploadSession(uploadSession); + } + else + { + uploadSession.File = RestoreIds(uploadSession.File); + } + } + + private File FinalizeUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("OneDriveSession")) + { + var oneDriveSession = uploadSession.GetItemOrDefault("OneDriveSession"); + + OneDriveProviderInfo.CacheReset(oneDriveSession.FileId); + var parentDriveId = oneDriveSession.FolderId; + if (parentDriveId != null) OneDriveProviderInfo.CacheReset(parentDriveId); + + return ToFile(GetOneDriveItem(oneDriveSession.FileId)); + } + + using (var fs = new FileStream(uploadSession.GetItemOrDefault("TempPath"), FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + return SaveFile(uploadSession.File, fs); + } + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("OneDriveSession")) + { + var oneDriveSession = uploadSession.GetItemOrDefault("OneDriveSession"); + + if (oneDriveSession.Status != ResumableUploadSessionStatus.Completed) + { + OneDriveProviderInfo.Storage.CancelTransfer(oneDriveSession); + + oneDriveSession.Status = ResumableUploadSessionStatus.Aborted; + } + } + else if (uploadSession.Items.ContainsKey("TempPath")) + { + System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + } + } + + #endregion + + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class OneDriveFileDaoExtention + { + public static DIHelper AddOneDriveFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs new file mode 100644 index 0000000000..fade47f7a6 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs @@ -0,0 +1,425 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveFolderDao : OneDriveDaoBase, IFolderDao + { + public OneDriveFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public Folder GetFolder(string folderId) + { + return ToFolder(GetOneDriveItem(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + return ToFolder(GetOneDriveItems(parentId, true) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase) && item.Folder != null)); + } + + public Folder GetRootFolderByFile(string fileId) + { + return GetRootFolder(fileId); + } + + public List> GetFolders(string parentId) + { + return GetOneDriveItems(parentId, true).Select(ToFolder).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); //TODO:!!! + //Filter + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateBy) : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.ModifiedOn) : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateOn) : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + + while (folderId != null) + { + var onedriveFolder = GetOneDriveItem(folderId); + + if (onedriveFolder is ErrorItem) + { + folderId = null; + } + else + { + path.Add(ToFolder(onedriveFolder)); + folderId = GetParentFolderId(onedriveFolder); + } + } + + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + if (folder == null) throw new ArgumentNullException("folder"); + if (folder.ID != null) + { + return RenameFolder(folder, folder.Title); + } + + if (folder.ParentFolderID != null) + { + var onedriveFolderId = MakeOneDriveId(folder.ParentFolderID); + + folder.Title = GetAvailableTitle(folder.Title, onedriveFolderId, IsExist); + + var onedriveFolder = OneDriveProviderInfo.Storage.CreateFolder(folder.Title, onedriveFolderId); + + OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + var parentFolderId = GetParentFolderId(onedriveFolder); + if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + + return MakeId(onedriveFolder); + } + return null; + } + + public bool IsExist(string title, string folderId) + { + return GetOneDriveItems(folderId, true) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public void DeleteFolder(string folderId) + { + var onedriveFolder = GetOneDriveItem(folderId); + var id = MakeId(onedriveFolder); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(onedriveFolder is ErrorItem)) + OneDriveProviderInfo.Storage.DeleteItem(onedriveFolder); + + OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + var parentFolderId = GetParentFolderId(onedriveFolder); + if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var onedriveFolder = GetOneDriveItem(folderId); + if (onedriveFolder is ErrorItem) throw new Exception(((ErrorItem)onedriveFolder).Error); + + var toOneDriveFolder = GetOneDriveItem(toFolderId); + if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); + + var fromFolderId = GetParentFolderId(onedriveFolder); + + var newTitle = GetAvailableTitle(onedriveFolder.Name, toOneDriveFolder.Id, IsExist); + onedriveFolder = OneDriveProviderInfo.Storage.MoveItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); + + OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + OneDriveProviderInfo.CacheReset(fromFolderId); + OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + + return MakeId(onedriveFolder.Id); + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var onedriveFolder = GetOneDriveItem(folderId); + if (onedriveFolder is ErrorItem) throw new Exception(((ErrorItem)onedriveFolder).Error); + + var toOneDriveFolder = GetOneDriveItem(toFolderId); + if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); + + var newTitle = GetAvailableTitle(onedriveFolder.Name, toOneDriveFolder.Id, IsExist); + var newOneDriveFolder = OneDriveProviderInfo.Storage.CopyItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); + + OneDriveProviderInfo.CacheReset(newOneDriveFolder.Id); + OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + + return ToFolder(newOneDriveFolder); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var onedriveFolder = GetOneDriveItem(folder.ID); + var parentFolderId = GetParentFolderId(onedriveFolder); + + if (IsRoot(onedriveFolder)) + { + //It's root folder + OneDriveDaoSelector.RenameProvider(OneDriveProviderInfo, newTitle); + //rename provider customer title + } + else + { + newTitle = GetAvailableTitle(newTitle, parentFolderId, IsExist); + + //rename folder + onedriveFolder = OneDriveProviderInfo.Storage.RenameItem(onedriveFolder.Id, newTitle); + } + + OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + + return MakeId(onedriveFolder.Id); + } + + public int GetItemsCount(string folderId) + { + var onedriveFolder = GetOneDriveItem(folderId); + return (onedriveFolder == null + || onedriveFolder.Folder == null + || !onedriveFolder.Folder.ChildCount.HasValue) + ? 0 + : onedriveFolder.Folder.ChildCount.Value; + } + + public bool IsEmpty(string folderId) + { + var onedriveFolder = GetOneDriveItem(folderId); + return onedriveFolder == null + || onedriveFolder.Folder == null + || onedriveFolder.Folder.ChildCount == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return false; + } + + public bool CanCalculateSubitems(string entryId) + { + return true; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var storageMaxUploadSize = OneDriveProviderInfo.Storage.MaxChunkedUploadFileSize; + + return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } + + public static class OneDriveFolderDaoExtention + { + public static DIHelper AddOneDriveFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs new file mode 100644 index 0000000000..1132cf4f04 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -0,0 +1,266 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Core.Common.Configuration; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OneDrive.Sdk; + +namespace ASC.Files.Thirdparty.OneDrive +{ + [DebuggerDisplay("{CustomerTitle}")] + internal class OneDriveProviderInfo : IProviderInfo, IDisposable + { + public OAuth20Token Token { get; set; } + + internal OneDriveStorage Storage + { + get + { + if (Wrapper.Storage == null || !Wrapper.Storage.IsOpened) + { + return Wrapper.CreateStorage(Token, ID); + } + return Wrapper.Storage; + } + } + + internal bool StorageOpened + { + get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; + } + + public int ID { get; set; } + + public Guid Owner { get; set; } + + public string CustomerTitle { get; set; } + + public DateTime CreateOn { get; set; } + + public string RootFolderId + { + get { return "onedrive-" + ID; } + } + + public string ProviderKey { get; set; } + + public FolderType RootFolderType { get; set; } + public OneDriveStorageDisposableWrapper Wrapper { get; } + public OneDriveProviderInfoHelper OneDriveProviderInfoHelper { get; } + + public OneDriveProviderInfo( + OneDriveStorageDisposableWrapper wrapper, + OneDriveProviderInfoHelper oneDriveProviderInfoHelper) + { + Wrapper = wrapper; + OneDriveProviderInfoHelper = oneDriveProviderInfoHelper; + } + + public void Dispose() + { + if (StorageOpened) + Storage.Close(); + } + + public bool CheckAccess() + { + try + { + return Storage.CheckAccess(); + } + catch (AggregateException) + { + return false; + } + } + + public void InvalidateStorage() + { + if (Wrapper != null) + { + Wrapper.Dispose(); + } + + CacheReset(); + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + internal Item GetOneDriveItem(string itemId) + { + return OneDriveProviderInfoHelper.GetOneDriveItem(Storage, ID, itemId); + } + + internal List GetOneDriveItems(string onedriveFolderId) + { + return OneDriveProviderInfoHelper.GetOneDriveItems(Storage, ID, onedriveFolderId); + } + + internal void CacheReset(string onedriveId = null) + { + OneDriveProviderInfoHelper.CacheReset(ID, onedriveId); + } + } + + internal class OneDriveStorageDisposableWrapper : IDisposable + { + public OneDriveStorage Storage { get; private set; } + public ConsumerFactory ConsumerFactory { get; } + public IServiceProvider ServiceProvider { get; } + + public OneDriveStorageDisposableWrapper(ConsumerFactory consumerFactory, IServiceProvider serviceProvider) + { + ConsumerFactory = consumerFactory; + ServiceProvider = serviceProvider; + } + + public OneDriveStorage CreateStorage(OAuth20Token token, int id) + { + if (Storage != null) return Storage; + + var onedriveStorage = ServiceProvider.GetService(); + + CheckToken(token, id); + + onedriveStorage.Open(token); + return Storage = onedriveStorage; + } + + private void CheckToken(OAuth20Token token, int id) + { + if (token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token"); + if (token.IsExpired) + { + token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, token); + + var dbDao = ServiceProvider.GetService(); + var authData = new AuthData(token: token.ToJson()); + dbDao.UpdateProviderInfo(id, authData); + } + } + + public void Dispose() + { + Storage.Close(); + } + } + + public class OneDriveProviderInfoHelper + { + private readonly TimeSpan CacheExpiration; + private readonly ICache CacheItem; + private readonly ICache CacheChildItems; + private readonly ICacheNotify CacheNotify; + + public OneDriveProviderInfoHelper(ICacheNotify cacheNotify) + { + CacheExpiration = TimeSpan.FromMinutes(1); + CacheItem = AscCache.Memory; + CacheChildItems = AscCache.Memory; + + CacheNotify = cacheNotify; + CacheNotify.Subscribe((i) => + { + if (i.ResetAll) + { + CacheChildItems.Remove(new Regex("^onedrivei-" + i.Key + ".*")); + CacheItem.Remove(new Regex("^onedrive-" + i.Key + ".*")); + } + else + { + CacheChildItems.Remove(new Regex("onedrivei-" + i.Key)); + CacheItem.Remove("onedrive-" + i.Key); + } + }, CacheNotifyAction.Remove); + } + + internal Item GetOneDriveItem(OneDriveStorage storage, int id, string itemId) + { + var file = CacheItem.Get("onedrive-" + id + "-" + itemId); + if (file == null) + { + file = storage.GetItem(itemId); + if (file != null) + CacheItem.Insert("onedrive-" + id + "-" + itemId, file, DateTime.UtcNow.Add(CacheExpiration)); + } + return file; + } + + internal List GetOneDriveItems(OneDriveStorage storage, int id, string onedriveFolderId) + { + var items = CacheChildItems.Get>("onedrivei-" + id + "-" + onedriveFolderId); + + if (items == null) + { + items = storage.GetItems(onedriveFolderId); + CacheChildItems.Insert("onedrivei-" + id + "-" + onedriveFolderId, items, DateTime.UtcNow.Add(CacheExpiration)); + } + return items; + } + + internal void CacheReset(int id, string onedriveId = null) + { + var key = id + "-"; + if (string.IsNullOrEmpty(onedriveId)) + { + CacheNotify.Publish(new OneDriveCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove); + } + else + { + key += onedriveId; + + CacheNotify.Publish(new OneDriveCacheItem { Key = key }, CacheNotifyAction.Remove); + } + } + } + + public static class OneDriveProviderInfoExtension + { + public static DIHelper AddOneDriveProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddSingleton(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs new file mode 100644 index 0000000000..47c2865649 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs @@ -0,0 +1,106 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveSecurityDao : OneDriveDaoBase, ISecurityDao + { + public OneDriveSecurityDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + } + + public static class OneDriveSecurityDaoExtention + { + public static DIHelper AddOneDriveSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveStorage.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveStorage.cs new file mode 100644 index 0000000000..ad345e6c5a --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveStorage.cs @@ -0,0 +1,392 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; + +using ASC.Core.Common.Configuration; +using ASC.FederatedLogin; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; + +using Microsoft.Graph; +using Microsoft.OneDrive.Sdk; + +using Newtonsoft.Json.Linq; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveStorage + { + public OneDriveStorage(ConsumerFactory consumerFactory) + { + ConsumerFactory = consumerFactory; + } + + private OAuth20Token _token; + + private string AccessToken + { + get + { + if (_token == null) throw new Exception("Cannot create OneDrive session with given token"); + if (_token.IsExpired) + { + _token = OAuth20TokenHelper.RefreshToken(ConsumerFactory, _token); + _onedriveClientCache = null; + } + return _token.AccessToken; + } + } + + private OneDriveClient _onedriveClientCache; + + private OneDriveClient OnedriveClient + { + get { return _onedriveClientCache ?? (_onedriveClientCache = new OneDriveClient(new OneDriveAuthProvider(AccessToken))); } + } + + public bool IsOpened { get; private set; } + public ConsumerFactory ConsumerFactory { get; } + + public long MaxChunkedUploadFileSize = 10L * 1024L * 1024L * 1024L; + + public void Open(OAuth20Token token) + { + if (IsOpened) + return; + + _token = token; + + IsOpened = true; + } + + public void Close() + { + IsOpened = false; + } + + public bool CheckAccess() + { + return OnedriveClient + .Drive + .Request() + .GetAsync() + .Result != null; + } + + + public static string RootPath = "/drive/root:"; + public static string ApiVersion = "v1.0"; + + public static string MakeOneDrivePath(string parentPath, string name) + { + return (parentPath ?? "") + "/" + (name ?? ""); + } + + public Item GetItem(string itemId) + { + try + { + return GetItemRequest(itemId).Request().GetAsync().Result; + } + catch (Exception ex) + { + var serviceException = (ServiceException)ex.InnerException; + if (serviceException != null && serviceException.StatusCode == HttpStatusCode.NotFound) + { + return null; + } + throw; + } + } + + public List GetItems(string folderId, int limit = 500) + { + return new List(GetItemRequest(folderId).Children.Request().GetAsync().Result); + } + + public Stream DownloadStream(Item file, int offset = 0) + { + if (file == null || file.File == null) throw new ArgumentNullException("file"); + + var fileStream = OnedriveClient + .Drive + .Items[file.Id] + .Content + .Request() + .GetAsync() + .Result; + + if (fileStream != null && offset > 0) + fileStream.Seek(offset, SeekOrigin.Begin); + + return fileStream; + } + + public Item CreateFolder(string title, string parentId) + { + var newFolderItem = new Item + { + Folder = new Folder(), + Name = title + }; + + return GetItemRequest(parentId) + .Children + .Request() + .AddAsync(newFolderItem) + .Result; + } + + public Item CreateFile(Stream fileStream, string title, string parentPath) + { + return OnedriveClient + .Drive + .Root + .ItemWithPath(MakeOneDrivePath(parentPath, title)) + .Content + .Request() + .PutAsync(fileStream) + .Result; + } + + public void DeleteItem(Item item) + { + OnedriveClient + .Drive + .Items[item.Id] + .Request() + .DeleteAsync(); + } + + public Item MoveItem(string itemId, string newItemName, string toFolderId) + { + var updateItem = new Item { ParentReference = new ItemReference { Id = toFolderId }, Name = newItemName }; + + return OnedriveClient + .Drive + .Items[itemId] + .Request() + .UpdateAsync(updateItem) + .Result; + } + + public Item CopyItem(string itemId, string newItemName, string toFolderId) + { + var copyMonitor = OnedriveClient + .Drive + .Items[itemId] + .Copy(newItemName, new ItemReference { Id = toFolderId }) + .Request() + .PostAsync() + .Result; + + return copyMonitor.PollForOperationCompletionAsync(null, CancellationToken.None).Result; + } + + public Item RenameItem(string itemId, string newName) + { + var updateItem = new Item { Name = newName }; + return OnedriveClient + .Drive + .Items[itemId] + .Request() + .UpdateAsync(updateItem) + .Result; + } + + public Item SaveStream(string fileId, Stream fileStream) + { + return OnedriveClient + .Drive + .Items[fileId] + .Content + .Request() + .PutAsync(fileStream) + .Result; + } + + private IItemRequestBuilder GetItemRequest(string itemId) + { + return string.IsNullOrEmpty(itemId) + ? OnedriveClient.Drive.Root + : OnedriveClient.Drive.Items[itemId]; + } + + + public ResumableUploadSession CreateResumableSession(Item onedriveFile, long contentLength) + { + if (onedriveFile == null) throw new ArgumentNullException("onedriveFile"); + + var folderId = onedriveFile.ParentReference.Id; + var fileName = onedriveFile.Name; + + var uploadUriBuilder = new UriBuilder(OneDriveLoginProvider.OneDriveApiUrl) + { + Path = "/" + ApiVersion + "/drive/items/" + folderId + ":/" + fileName + ":/oneDrive.createUploadSession" + }; + + var request = WebRequest.Create(uploadUriBuilder.Uri); + request.Method = "POST"; + request.ContentLength = 0; + + request.ContentType = "application/json; charset=UTF-8"; + request.Headers.Add("Authorization", "Bearer " + AccessToken); + + var uploadSession = new ResumableUploadSession(onedriveFile.Id, folderId, contentLength); + using (var response = request.GetResponse()) + using (var responseStream = response.GetResponseStream()) + { + if (responseStream != null) + { + using (var readStream = new StreamReader(responseStream)) + { + var responseString = readStream.ReadToEnd(); + var responseJson = JObject.Parse(responseString); + uploadSession.Location = responseJson.Value("uploadUrl"); + } + } + } + + uploadSession.Status = ResumableUploadSessionStatus.Started; + + return uploadSession; + } + + public void Transfer(ResumableUploadSession oneDriveSession, Stream stream, long chunkLength) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (oneDriveSession.Status != ResumableUploadSessionStatus.Started) + throw new InvalidOperationException("Can't upload chunk for given upload session."); + + var request = WebRequest.Create(oneDriveSession.Location); + request.Method = "PUT"; + request.ContentLength = chunkLength; + request.Headers.Add("Authorization", "Bearer " + AccessToken); + request.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", + oneDriveSession.BytesTransfered, + oneDriveSession.BytesTransfered + chunkLength - 1, + oneDriveSession.BytesToTransfer)); + + using (var requestStream = request.GetRequestStream()) + { + stream.CopyTo(requestStream); + } + + using (var response = (HttpWebResponse)request.GetResponse()) + { + if (response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.OK) + { + oneDriveSession.BytesTransfered += chunkLength; + } + else + { + oneDriveSession.Status = ResumableUploadSessionStatus.Completed; + + using (var responseStream = response.GetResponseStream()) + { + if (responseStream == null) return; + using (var readStream = new StreamReader(responseStream)) + { + var responseString = readStream.ReadToEnd(); + var responseJson = JObject.Parse(responseString); + + oneDriveSession.FileId = responseJson.Value("id"); + } + } + } + } + } + + public void CancelTransfer(ResumableUploadSession oneDriveSession) + { + var request = WebRequest.Create(oneDriveSession.Location); + request.Method = "DELETE"; + using (request.GetResponse()) + { + } + } + } + + + + public class OneDriveAuthProvider : IAuthenticationProvider + { + private readonly string _accessToken; + + public OneDriveAuthProvider(string accessToken) + { + _accessToken = accessToken; + } + + public Task AuthenticateRequestAsync(HttpRequestMessage request) + { + request.Headers.Authorization = new AuthenticationHeaderValue("bearer", _accessToken); + return Task.WhenAll(); + } + } + + public enum ResumableUploadSessionStatus + { + None, + Started, + Completed, + Aborted + } + + [Serializable] + internal class ResumableUploadSession + { + public long BytesToTransfer { get; set; } + + public long BytesTransfered { get; set; } + + public string FileId { get; set; } + + public string FolderId { get; set; } + + public ResumableUploadSessionStatus Status { get; set; } + + public string Location { get; set; } + + public ResumableUploadSession(string fileId, string folderId, long bytesToTransfer) + { + FileId = fileId; + FolderId = folderId; + BytesToTransfer = bytesToTransfer; + Status = ResumableUploadSessionStatus.None; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs new file mode 100644 index 0000000000..5cc32b8ce8 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs @@ -0,0 +1,182 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.OneDrive +{ + internal class OneDriveTagDao : OneDriveDaoBase, ITagDao + { + public OneDriveTagDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + #region ITagDao Members + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + var folderId = OneDriveDaoSelector.ConvertId(parentFolder.ID); + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(GetChildren(folderId)); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return null; + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return null; + } + + public IEnumerable SaveTags(Tag tag) + { + return null; + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return null; + } + + public void MarkAsNew(Guid subject, FileEntry fileEntry) + { + } + + #endregion + } + + public static class OneDriveTagDaoExtention + { + public static DIHelper AddOneDriveTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index 5d5ca7da44..29c5068f14 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -43,6 +43,8 @@ using ASC.Files.Resources; using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; using ASC.Files.Thirdparty.GoogleDrive; +using ASC.Files.Thirdparty.OneDrive; +using ASC.Files.Thirdparty.SharePoint; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; @@ -375,6 +377,8 @@ namespace ASC.Files.Thirdparty var folderType = input.FolderType; var createOn = TenantUtil.DateTimeFromUtc(input.CreateOn); + if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null"); + if (key == ProviderTypes.Box) { var box = ServiceProvider.GetService(); @@ -390,8 +394,6 @@ namespace ASC.Files.Thirdparty if (key == ProviderTypes.DropboxV2) { - if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null"); - var drop = ServiceProvider.GetService(); drop.ID = id; drop.CustomerTitle = providerTitle; @@ -404,41 +406,51 @@ namespace ASC.Files.Thirdparty return drop; } - //if (key == ProviderTypes.SharePoint) - //{ - // return new SharePointProviderInfo( - // id, - // key.ToString(), - // providerTitle, - // new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token), - // owner, - // folderType, - // createOn); - //} + if (key == ProviderTypes.SharePoint) + { + var authData = new AuthData(input.Url, input.UserName, DecryptPassword(input.Password), token); - //if (key == ProviderTypes.GoogleDrive) - //{ - // return new GoogleDriveProviderInfo( - // id, - // key.ToString(), - // providerTitle, - // token, - // owner, - // folderType, - // createOn); - //} + if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password)) + throw new ArgumentNullException("password", "Password can't be null"); - //if (key == ProviderTypes.OneDrive) - //{ - // return new OneDriveProviderInfo( - // id, - // key.ToString(), - // providerTitle, - // token, - // owner, - // folderType, - // createOn); - //} + var sh = ServiceProvider.GetService(); + sh.ID = id; + sh.CustomerTitle = providerTitle; + sh.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + sh.ProviderKey = input.Provider; + sh.RootFolderType = folderType; + sh.CreateOn = createOn; + sh.InitClientContext(authData); + return sh; + } + + if (key == ProviderTypes.GoogleDrive) + { + var gd = ServiceProvider.GetService(); + gd.ID = id; + gd.CustomerTitle = providerTitle; + gd.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + gd.ProviderKey = input.Provider; + gd.RootFolderType = folderType; + gd.CreateOn = createOn; + gd.Token = OAuth20Token.FromJson(token); + + return gd; + } + + if (key == ProviderTypes.OneDrive) + { + var od = ServiceProvider.GetService(); + od.ID = id; + od.CustomerTitle = providerTitle; + od.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + od.ProviderKey = input.Provider; + od.RootFolderType = folderType; + od.CreateOn = createOn; + od.Token = OAuth20Token.FromJson(token); + + return od; + } //return new SharpBoxProviderInfo( // id, @@ -571,6 +583,8 @@ namespace ASC.Files.Thirdparty //services.TryAddScoped(); return services + .AddSharePointProviderInfoService() + .AddOneDriveProviderInfoService() .AddGoogleDriveProviderInfoService() .AddBoxProviderInfoService() .AddDropboxProviderInfoService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index bcb8546a8b..230c0c62d7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -36,6 +36,8 @@ using ASC.Files.Resources; using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; using ASC.Files.Thirdparty.GoogleDrive; +using ASC.Files.Thirdparty.OneDrive; +using ASC.Files.Thirdparty.SharePoint; using ASC.Web.Files.Utils; using ASC.Web.Studio.Core; @@ -64,12 +66,12 @@ namespace ASC.Files.Thirdparty.ProviderDao //Fill in selectors //Selectors.Add(new SharpBoxDaoSelector()); - //Selectors.Add(new SharePointDaoSelector()); + ServiceProvider.GetService(), ServiceProvider.GetService(), ServiceProvider.GetService(), - ServiceProvider.GetService() + ServiceProvider.GetService(), + ServiceProvider.GetService() }; - // Selectors.Add(new OneDriveDaoSelector()); } public IServiceProvider ServiceProvider { get; } @@ -265,6 +267,8 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderDaoBaseService(this DIHelper services) { return services + .AddSharePointSelectorService() + .AddOneDriveSelectorService() .AddGoogleDriveSelectorService() .AddDropboxDaoSelectorService() .AddBoxDaoSelectorService(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs new file mode 100644 index 0000000000..f5e8c8ac93 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs @@ -0,0 +1,210 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Linq; +using System.Text.RegularExpressions; + +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Security.Cryptography; +using ASC.Web.Studio.Core; + +using Microsoft.EntityFrameworkCore; + +using Folder = Microsoft.SharePoint.Client.Folder; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointDaoBase + { + public SharePointProviderInfo ProviderInfo { get; private set; } + public SharePointDaoSelector SharePointDaoSelector { get; private set; } + + public SharePointDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo) + { + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + TenantID = tenantManager.GetCurrentTenant().TenantId; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + SetupInfo = setupInfo; + } + + public void Init(SharePointProviderInfo sharePointInfo, SharePointDaoSelector sharePointDaoSelector) + { + ProviderInfo = sharePointInfo; + SharePointDaoSelector = sharePointDaoSelector; + } + + protected int TenantID { get; set; } + + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantUtil TenantUtil { get; } + public FilesDbContext FilesDbContext { get; } + public SetupInfo SetupInfo { get; } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + protected string GetAvailableTitle(string requestTitle, Folder parentFolderID, Func isExist) + { + if (!isExist(requestTitle, parentFolderID)) return requestTitle; + + var re = new Regex(@"( \(((?[0-9])+)\)(\.[^\.]*)?)$"); + var match = re.Match(requestTitle); + + if (!match.Success) + { + var insertIndex = requestTitle.Length; + if (requestTitle.LastIndexOf(".", StringComparison.Ordinal) != -1) + { + insertIndex = requestTitle.LastIndexOf(".", StringComparison.Ordinal); + } + requestTitle = requestTitle.Insert(insertIndex, " (1)"); + } + + while (isExist(requestTitle, parentFolderID)) + { + requestTitle = re.Replace(requestTitle, MatchEvaluator); + } + return requestTitle; + } + + private static string MatchEvaluator(Match match) + { + var index = Convert.ToInt32(match.Groups[2].Value); + var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); + return string.Format(" ({0}){1}", index + 1, staticText); + } + + protected string MappingID(string id, bool saveIfNotExist) + { + if (id == null) return null; + + string result; + + if (id.ToString().StartsWith("spoint")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + + return result; + } + + protected void UpdatePathInDB(string oldValue, string newValue) + { + if (oldValue.Equals(newValue)) return; + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var oldIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(oldValue)) + .Select(r => r.Id) + .ToList(); + + foreach (var oldID in oldIDs) + { + var oldHashID = MappingID(oldID); + var newID = oldID.Replace(oldValue, newValue); + var newHashID = MappingID(newID); + + var mappingForUpdate = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.HashId == oldHashID) + .ToList(); + + foreach (var m in mappingForUpdate) + { + m.Id = newID; + m.HashId = newHashID; + } + + FilesDbContext.SaveChanges(); + + var securityForUpdate = Query(FilesDbContext.Security) + .Where(r => r.EntryId == oldHashID) + .ToList(); + + foreach (var s in securityForUpdate) + { + s.EntryId = newHashID; + } + + FilesDbContext.SaveChanges(); + + var linkForUpdate = Query(FilesDbContext.TagLink) + .Where(r => r.EntryId == oldHashID) + .ToList(); + + foreach (var l in linkForUpdate) + { + l.EntryId = newHashID; + } + + FilesDbContext.SaveChanges(); + } + + tx.Commit(); + } + } + + protected string MappingID(string id) + { + return MappingID(id, false); + } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs new file mode 100644 index 0000000000..af87606c78 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs @@ -0,0 +1,163 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointDaoSelector : RegexDaoSelectorBase + { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } + + public SharePointDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) + : base(new Regex(@"^spoint-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override IFolderDao GetFolderDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ITagDao GetTagDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ISecurityDao GetSecurityDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return GetInfo(id).SpRootFolderId + match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a sharepoint id"); + } + return base.ConvertId(null); + } + + private SharePointProviderInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + return GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + } + throw new ArgumentException("Id is not a sharepoint id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private SharePointProviderInfo GetProviderInfo(int linkId) + { + SharePointProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + + try + { + info = (SharePointProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(SharePointProviderInfo sharePointProviderInfo, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(sharePointProviderInfo.ID, newTitle, null, sharePointProviderInfo.RootFolderType); + sharePointProviderInfo.UpdateTitle(newTitle); //This will update cached version too + } + } + + public static class SharePointDaoSelectorExtention + { + public static DIHelper AddSharePointSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddSharePointSecurityDaoService() + .AddSharePointTagDaoService() + .AddSharePointFolderDaoService() + .AddSharePointFileDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointErrorEntry.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointErrorEntry.cs new file mode 100644 index 0000000000..66183cc080 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointErrorEntry.cs @@ -0,0 +1,54 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using Microsoft.SharePoint.Client; + +namespace ASC.Files.Thirdparty.SharePoint +{ + public class SharePointFileErrorEntry : File + { + public SharePointFileErrorEntry(ClientRuntimeContext cc, ObjectPath op) + : base(cc, op) + { + } + + public string Error { get; set; } + + public object ID { get; set; } + } + + public class SharePointFolderErrorEntry : Folder + { + public SharePointFolderErrorEntry(ClientRuntimeContext cc, ObjectPath op) + : base(cc, op) + { + } + + public string Error { get; set; } + + public object ID { get; set; } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs new file mode 100644 index 0000000000..2d64429822 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -0,0 +1,431 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointFileDao : SharePointDaoBase, IFileDao + { + public SharePointFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void Dispose() + { + ProviderInfo.Dispose(); + } + + public void InvalidateCache(string fileId) + { + ProviderInfo.InvalidateStorage(); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ProviderInfo.ToFile(ProviderInfo.GetFileById(fileId)); + } + + public File GetFile(string parentId, string title) + { + return ProviderInfo.ToFile(ProviderInfo.GetFolderFiles(parentId).FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase))); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ProviderInfo.ToFile(ProviderInfo.GetFileById(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + return fileIds.Select(fileId => ProviderInfo.ToFile(ProviderInfo.GetFileById(fileId))).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + return ProviderInfo.GetFolderFiles(parentId).Select(r => ProviderInfo.ToFile(r).ID).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = ProviderInfo.GetFolderFiles(parentId).Select(r => ProviderInfo.ToFile(r)); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document).ToList(); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation).ToList(); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet).ToList(); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image).ToList(); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive).ToList(); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1).ToList(); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public Stream GetFileStream(File file, long offset) + { + var fileToDownload = ProviderInfo.GetFileById(file.ID); + if (fileToDownload == null) + throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + + var fileStream = ProviderInfo.GetFileStream(fileToDownload.ServerRelativeUrl, (int)offset); + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public File SaveFile(File file, Stream fileStream) + { + if (fileStream == null) throw new ArgumentNullException("fileStream"); + + if (file.ID != null) + { + var sharePointFile = ProviderInfo.CreateFile(file.ID, fileStream); + + var resultFile = ProviderInfo.ToFile(sharePointFile); + if (!sharePointFile.Name.Equals(file.Title)) + { + var folder = ProviderInfo.GetFolderById(file.FolderID); + file.Title = GetAvailableTitle(file.Title, folder, IsExist); + + var id = ProviderInfo.RenameFile(SharePointDaoSelector.ConvertId(resultFile.ID).ToString(), file.Title); + return GetFile(SharePointDaoSelector.ConvertId(id)); + } + return resultFile; + } + + if (file.FolderID != null) + { + var folder = ProviderInfo.GetFolderById(file.FolderID); + file.Title = GetAvailableTitle(file.Title, folder, IsExist); + return ProviderInfo.ToFile(ProviderInfo.CreateFile(folder.ServerRelativeUrl + "/" + file.Title, fileStream)); + } + + return null; + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + ProviderInfo.DeleteFile(fileId); + } + + public bool IsExist(string title, object folderId) + { + return ProviderInfo.GetFolderFiles(folderId) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public bool IsExist(string title, Microsoft.SharePoint.Client.Folder folder) + { + return ProviderInfo.GetFolderFiles(folder.ServerRelativeUrl) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public string MoveFile(string fileId, string toFolderId) + { + var newFileId = ProviderInfo.MoveFile(fileId, toFolderId); + UpdatePathInDB(ProviderInfo.MakeId(fileId), newFileId); + return newFileId; + } + + public File CopyFile(string fileId, string toFolderId) + { + return ProviderInfo.ToFile(ProviderInfo.CopyFile(fileId, toFolderId)); + } + + public string FileRename(File file, string newTitle) + { + var newFileId = ProviderInfo.RenameFile(file.ID, newTitle); + UpdatePathInDB(ProviderInfo.MakeId(file.ID), newFileId); + return newFileId; + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + return new ChunkedUploadSession(FixId(file), contentLength) { UseChunks = false }; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, chunkStream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + throw new NotImplementedException(); + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + //throw new NotImplementedException(); + } + + private File FixId(File file) + { + if (file.ID != null) + file.ID = ProviderInfo.MakeId(file.ID); + + if (file.FolderID != null) + file.FolderID = ProviderInfo.MakeId(file.FolderID); + + return file; + } + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class SharePointFileDaoExtention + { + public static DIHelper AddSharePointFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs new file mode 100644 index 0000000000..1b80bf7465 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs @@ -0,0 +1,379 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointFolderDao : SharePointDaoBase, IFolderDao + { + public SharePointFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void Dispose() + { + ProviderInfo.Dispose(); + } + + public Folder GetFolder(string folderId) + { + return ProviderInfo.ToFolder(ProviderInfo.GetFolderById(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + return + ProviderInfo.ToFolder( + ProviderInfo.GetFolderFolders(parentId) + .FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase))); + } + + public Folder GetRootFolder(string folderId) + { + return ProviderInfo.ToFolder(ProviderInfo.RootFolder); + } + + public Folder GetRootFolderByFile(string fileId) + { + return ProviderInfo.ToFolder(ProviderInfo.RootFolder); + } + + public List> GetFolders(string parentId) + { + return ProviderInfo.GetFolderFolders(parentId).Select(r => ProviderInfo.ToFolder(r)).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc + ? folders.OrderBy(x => x.CreateBy) + : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc + ? folders.OrderBy(x => x.ModifiedOn) + : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc + ? folders.OrderBy(x => x.CreateOn) + : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + var folder = ProviderInfo.GetFolderById(folderId); + if (folder != null) + { + do + { + path.Add(ProviderInfo.ToFolder(folder)); + } while (folder != ProviderInfo.RootFolder && !(folder is SharePointFolderErrorEntry) && + (folder = ProviderInfo.GetParentFolder(folder.ServerRelativeUrl)) != null); + } + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + if (folder.ID != null) + { + //Create with id + var savedfolder = ProviderInfo.CreateFolder(folder.ID); + return ProviderInfo.ToFolder(savedfolder).ID; + } + + if (folder.ParentFolderID != null) + { + var parentFolder = ProviderInfo.GetFolderById(folder.ParentFolderID); + + folder.Title = GetAvailableTitle(folder.Title, parentFolder, IsExist); + + var newFolder = ProviderInfo.CreateFolder(parentFolder.ServerRelativeUrl + "/" + folder.Title); + return ProviderInfo.ToFolder(newFolder).ID; + } + + return null; + } + + public bool IsExist(string title, Microsoft.SharePoint.Client.Folder folder) + { + return ProviderInfo.GetFolderFolders(folder.ServerRelativeUrl) + .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); + } + + public void DeleteFolder(string folderId) + { + var folder = ProviderInfo.GetFolderById(folderId); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(folder.ServerRelativeUrl)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + ProviderInfo.DeleteFolder(folderId); + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var newFolderId = ProviderInfo.MoveFolder(folderId, toFolderId); + UpdatePathInDB(ProviderInfo.MakeId(folderId), newFolderId); + return newFolderId; + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + return ProviderInfo.ToFolder(ProviderInfo.CopyFolder(folderId, toFolderId)); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var oldId = ProviderInfo.MakeId(folder.ID); + var newFolderId = oldId; + if (ProviderInfo.SpRootFolderId.Equals(folder.ID)) + { + //It's root folder + SharePointDaoSelector.RenameProvider(ProviderInfo, newTitle); + //rename provider customer title + } + else + { + newFolderId = (string)ProviderInfo.RenameFolder(folder.ID, newTitle); + } + UpdatePathInDB(oldId, newFolderId); + return newFolderId; + } + + public int GetItemsCount(string folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(string folderId) + { + return ProviderInfo.GetFolderById(folderId).ItemCount == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return false; + } + + public bool CanCalculateSubitems(string entryId) + { + return false; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload = false) + { + return 2L * 1024L * 1024L * 1024L; + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, + bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } + + public static class SharePointFolderDaoExtention + { + public static DIHelper AddSharePointFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs new file mode 100644 index 0000000000..f22f938563 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs @@ -0,0 +1,677 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Security; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Common.Logging; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Web.Files.Classes; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.SharePoint.Client; + +using File = Microsoft.SharePoint.Client.File; +using Folder = Microsoft.SharePoint.Client.Folder; + +namespace ASC.Files.Thirdparty.SharePoint +{ + public class SharePointProviderInfo : IProviderInfo, IDisposable + { + private ClientContext clientContext; + + public int ID { get; set; } + public string ProviderKey { get; set; } + public Guid Owner { get; set; } + public FolderType RootFolderType { get; set; } + public DateTime CreateOn { get; set; } + public string CustomerTitle { get; set; } + public string RootFolderId { get { return "spoint-" + ID; } } + + public string SpRootFolderId = "/Shared Documents"; + + public SharePointProviderInfo( + IOptionsMonitor options, + IServiceProvider serviceProvider, + TenantUtil tenantUtil, + SharePointProviderInfoHelper sharePointProviderInfoHelper) + { + Log = options.CurrentValue; + ServiceProvider = serviceProvider; + TenantUtil = tenantUtil; + SharePointProviderInfoHelper = sharePointProviderInfoHelper; + } + + public bool CheckAccess() + { + try + { + clientContext.Load(clientContext.Web); + clientContext.ExecuteQuery(); + return true; + } + catch (Exception e) + { + Log.Warn("CheckAccess", e); + return false; + } + } + + public void InvalidateStorage() + { + clientContext.Dispose(); + SharePointProviderInfoHelper.Invalidate(); + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + + public void InitClientContext(AuthData authData) + { + var authUrl = authData.Url; + ICredentials credentials = new NetworkCredential(authData.Login, authData.Password); + + if (authData.Login.EndsWith("onmicrosoft.com")) + { + var personalPath = string.Concat("/personal/", authData.Login.Replace("@", "_").Replace(".", "_").ToLower()); + SpRootFolderId = string.Concat(personalPath, "/Documents"); + + var ss = new SecureString(); + foreach (var p in authData.Password) + { + ss.AppendChar(p); + } + authUrl = string.Concat(authData.Url.TrimEnd('/'), personalPath); + //TODO + //credentials = new SharePointOnlineCredentials(authData.Login, ss); + + } + + clientContext = new ClientContext(authUrl) + { + AuthenticationMode = ClientAuthenticationMode.Default, + Credentials = credentials + }; + } + + #region Files + + public File GetFileById(object id) + { + var key = "spointf-" + MakeId(id); + var file = SharePointProviderInfoHelper.GetFile(key); + if (file == null) + { + file = GetFile(id); + if (file != null) + { + SharePointProviderInfoHelper.AddFile(key, file); + } + } + return file; + } + + private File GetFile(object id) + { + var file = clientContext.Web.GetFileByServerRelativeUrl((string)id); + clientContext.Load(file); + clientContext.Load(file.ListItemAllFields); + + try + { + clientContext.ExecuteQuery(); + } + catch (Exception ex) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(GetParentFolderId(id))); + var serverException = (ServerException)ex; + if (serverException.ServerErrorTypeName == (typeof(FileNotFoundException)).ToString()) + { + return null; + } + return new SharePointFileErrorEntry(file.Context, file.Path) { Error = ex.Message, ID = id }; + } + + return file; + } + + public Stream GetFileStream(object id, int offset = 0) + { + var file = GetFileById(id); + + if (file is SharePointFileErrorEntry) return null; + var fileInfo = File.OpenBinaryDirect(clientContext, (string)id); + clientContext.ExecuteQuery(); + + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + using (var str = fileInfo.Stream) + { + if (str != null) + { + str.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(offset, SeekOrigin.Begin); + } + } + + return tempBuffer; + } + + public File CreateFile(string id, Stream stream) + { + byte[] b; + + using (var br = new BinaryReader(stream)) + { + b = br.ReadBytes((int)stream.Length); + } + + var file = clientContext.Web.RootFolder.Files.Add(new FileCreationInformation { Content = b, Url = id, Overwrite = true }); + clientContext.Load(file); + clientContext.Load(file.ListItemAllFields); + clientContext.ExecuteQuery(); + + SharePointProviderInfoHelper.AddFile("spointf-" + MakeId(id), file); + SharePointProviderInfoHelper.PublishFolder(MakeId(GetParentFolderId(id))); + + return file; + } + + public void DeleteFile(string id) + { + SharePointProviderInfoHelper.PublishFile(MakeId(id), MakeId(GetParentFolderId(id))); + + var file = GetFileById(id); + + if (file is SharePointFileErrorEntry) return; + + file.DeleteObject(); + clientContext.ExecuteQuery(); + } + + public string RenameFile(string id, string newTitle) + { + SharePointProviderInfoHelper.PublishFile(MakeId(id), MakeId(GetParentFolderId(id))); + + var file = GetFileById(id); + + if (file is SharePointFileErrorEntry) return MakeId(); + + var newUrl = GetParentFolderId(file.ServerRelativeUrl) + "/" + newTitle; + file.MoveTo(newUrl, MoveOperations.Overwrite); + clientContext.ExecuteQuery(); + + return MakeId(newUrl); + } + + public string MoveFile(string id, string toFolderId) + { + SharePointProviderInfoHelper.PublishFile(MakeId(id), MakeId(GetParentFolderId(id))); + SharePointProviderInfoHelper.PublishFolder(MakeId(toFolderId)); + + var file = GetFileById(id); + + if (file is SharePointFileErrorEntry) return MakeId(); + + var newUrl = toFolderId + "/" + file.Name; + file.MoveTo(newUrl, MoveOperations.Overwrite); + clientContext.ExecuteQuery(); + + return MakeId(newUrl); + } + + public File CopyFile(string id, string toFolderId) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(toFolderId), MakeId(GetParentFolderId(id))); + + var file = GetFileById(id); + + if (file is SharePointFileErrorEntry) return file; + + var newUrl = toFolderId + "/" + file.Name; + file.CopyTo(newUrl, false); + clientContext.ExecuteQuery(); + + return file; + } + + public File ToFile(File file) + { + if (file == null) + return null; + + var result = ServiceProvider.GetService>(); + + if (file is SharePointFileErrorEntry errorFile) + { + result.ID = MakeId(errorFile.ID); + result.FolderID = MakeId(GetParentFolderId(errorFile.ID)); + result.CreateBy = Owner; + result.CreateOn = DateTime.UtcNow; + result.ModifiedBy = Owner; + result.ModifiedOn = DateTime.UtcNow; + result.ProviderId = ID; + result.ProviderKey = ProviderKey; + result.RootFolderCreator = Owner; + result.RootFolderId = MakeId(RootFolder.ServerRelativeUrl); + result.RootFolderType = RootFolderType; + result.Title = MakeTitle(GetTitleById(errorFile.ID)); + result.Error = errorFile.Error; + + return result; + } + + result.ID = MakeId(file.ServerRelativeUrl); + result.Access = Core.Security.FileShare.None; + //ContentLength = file.Length, + result.CreateBy = Owner; + result.CreateOn = file.TimeCreated.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(file.TimeCreated) : file.TimeCreated; + result.FileStatus = FileStatus.None; + result.FolderID = MakeId(GetParentFolderId(file.ServerRelativeUrl)); + result.ModifiedBy = Owner; + result.ModifiedOn = file.TimeLastModified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(file.TimeLastModified) : file.TimeLastModified; + result.NativeAccessor = file; + result.ProviderId = ID; + result.ProviderKey = ProviderKey; + result.Title = MakeTitle(file.Name); + result.RootFolderId = MakeId(SpRootFolderId); + result.RootFolderType = RootFolderType; + result.RootFolderCreator = Owner; + result.Shared = false; + result.Version = 1; + + if (file.IsPropertyAvailable("Length")) + { + //TODO + //result.ContentLength = file.Length; + } + else if (file.IsObjectPropertyInstantiated("ListItemAllFields")) + { + result.ContentLength = Convert.ToInt64(file.ListItemAllFields["File_x0020_Size"]); + } + + return result; + } + + #endregion + + #region Folders + + public Folder RootFolder + { + get + { + var key = "spointd-" + MakeId(); + var folder = SharePointProviderInfoHelper.GetFolder(key); + if (folder == null) + { + folder = GetFolderById(SpRootFolderId); + SharePointProviderInfoHelper.AddFolder(key, folder); + } + return folder; + } + } + + public ILog Log { get; } + public IServiceProvider ServiceProvider { get; } + public TenantUtil TenantUtil { get; } + public SharePointProviderInfoHelper SharePointProviderInfoHelper { get; } + + public Folder GetFolderById(object id) + { + var key = "spointd-" + MakeId(id); + var folder = SharePointProviderInfoHelper.GetFolder(key); + if (folder == null) + { + folder = GetFolder(id); + if (folder != null) + { + SharePointProviderInfoHelper.AddFolder(key, folder); + } + } + return folder; + } + + private Folder GetFolder(object id) + { + if ((string)id == "") id = SpRootFolderId; + var folder = clientContext.Web.GetFolderByServerRelativeUrl((string)id); + clientContext.Load(folder); + clientContext.Load(folder.Files, collection => collection.IncludeWithDefaultProperties(r => r.ListItemAllFields)); + clientContext.Load(folder.Folders); + + try + { + clientContext.ExecuteQuery(); + } + catch (Exception ex) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(GetParentFolderId(id))); + var serverException = (ServerException)ex; + if (serverException.ServerErrorTypeName == (typeof(FileNotFoundException)).ToString()) + { + return null; + } + return new SharePointFolderErrorEntry(folder.Context, folder.Path) { Error = ex.Message, ID = id }; + } + + return folder; + } + + public Folder GetParentFolder(string serverRelativeUrl) + { + return GetFolderById(GetParentFolderId(serverRelativeUrl)); + } + + public IEnumerable GetFolderFiles(object id) + { + var folder = GetFolderById(id); + if (folder is SharePointFolderErrorEntry) return new List(); + + return GetFolderById(id).Files; + } + + public IEnumerable GetFolderFolders(object id) + { + var folder = GetFolderById(id); + if (folder is SharePointFolderErrorEntry) return new List(); + + return folder.Folders.ToList().Where(r => r.ServerRelativeUrl != SpRootFolderId + "/" + "Forms"); + } + + public object RenameFolder(object id, string newTitle) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(id), MakeId(GetParentFolderId(id))); + + var folder = GetFolderById(id); + if (folder is SharePointFolderErrorEntry) return MakeId(id); + + return MakeId(MoveFld(folder, GetParentFolderId(id) + "/" + newTitle).ServerRelativeUrl); + } + + public string MoveFolder(string id, string toFolderId) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(id), MakeId(GetParentFolderId(id)), MakeId(toFolderId)); + + var folder = GetFolderById(id); + if (folder is SharePointFolderErrorEntry) return MakeId(id); + + return MakeId(MoveFld(folder, toFolderId + "/" + GetFolderById(id).Name).ServerRelativeUrl); + } + + public Folder CopyFolder(object id, object toFolderId) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(toFolderId)); + + var folder = GetFolderById(id); + if (folder is SharePointFolderErrorEntry) return folder; + + return MoveFld(folder, toFolderId + "/" + GetFolderById(id).Name, false); + } + + private Folder MoveFld(Folder folder, string newUrl, bool delete = true) + { + var newFolder = CreateFolder(newUrl); + + if (delete) + { + folder.Folders.ToList().ForEach(r => MoveFolder(r.ServerRelativeUrl, newUrl)); + folder.Files.ToList().ForEach(r => MoveFile(r.ServerRelativeUrl, newUrl)); + + folder.DeleteObject(); + clientContext.ExecuteQuery(); + } + else + { + folder.Folders.ToList().ForEach(r => CopyFolder(r.ServerRelativeUrl, newUrl)); + folder.Files.ToList().ForEach(r => CopyFile(r.ServerRelativeUrl, newUrl)); + } + + return newFolder; + } + + public Folder CreateFolder(string id) + { + var folder = clientContext.Web.RootFolder.Folders.Add(id); + clientContext.Load(folder); + clientContext.ExecuteQuery(); + + SharePointProviderInfoHelper.CreateFolder(id, MakeId(GetParentFolderId(id)), folder); + return folder; + } + + public void DeleteFolder(string id) + { + SharePointProviderInfoHelper.PublishFolder(MakeId(id), MakeId(GetParentFolderId(id))); + + var folder = GetFolderById(id); + + if (folder is SharePointFolderErrorEntry) return; + + folder.DeleteObject(); + clientContext.ExecuteQuery(); + } + + public Folder ToFolder(Folder folder) + { + if (folder == null) return null; + + var result = ServiceProvider.GetService>(); + + if (folder is SharePointFolderErrorEntry errorFolder) + { + result.ID = MakeId(errorFolder.ID); + result.ParentFolderID = null; + result.CreateBy = Owner; + result.CreateOn = DateTime.UtcNow; + result.FolderType = FolderType.DEFAULT; + result.ModifiedBy = Owner; + result.ModifiedOn = DateTime.UtcNow; + result.ProviderId = ID; + result.ProviderKey = ProviderKey; + result.RootFolderCreator = Owner; + result.RootFolderId = MakeId(SpRootFolderId); + result.RootFolderType = RootFolderType; + result.Shareable = false; + result.Title = MakeTitle(GetTitleById(errorFolder.ID)); + result.TotalFiles = 0; + result.TotalSubFolders = 0; + result.Error = errorFolder.Error; + + return result; + } + + var isRoot = folder.ServerRelativeUrl == SpRootFolderId; + + result.ID = MakeId(isRoot ? "" : folder.ServerRelativeUrl); + result.ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(folder.ServerRelativeUrl)); + result.CreateBy = Owner; + result.CreateOn = CreateOn; + result.FolderType = FolderType.DEFAULT; + result.ModifiedBy = Owner; + result.ModifiedOn = CreateOn; + result.ProviderId = ID; + result.ProviderKey = ProviderKey; + result.RootFolderCreator = Owner; + result.RootFolderId = MakeId(RootFolder.ServerRelativeUrl); + result.RootFolderType = RootFolderType; + result.Shareable = false; + result.Title = isRoot ? CustomerTitle : MakeTitle(folder.Name); + result.TotalFiles = 0; + result.TotalSubFolders = 0; + + return result; + } + + #endregion + + public string MakeId(string path = "") + { + path = path.Replace(SpRootFolderId, ""); + return string.Format("{0}{1}", "spoint-" + ID, string.IsNullOrEmpty(path) || path == "/" || path == SpRootFolderId ? "" : ("-" + path.Replace('/', '|'))); + } + + private string MakeId(object path) + { + return MakeId((string)path); + } + + protected string MakeTitle(string name) + { + return Global.ReplaceInvalidCharsAndTruncate(name); + } + + protected string GetParentFolderId(string serverRelativeUrl) + { + var path = serverRelativeUrl.Split('/'); + + return string.Join("/", path.Take(path.Length - 1)); + } + + protected string GetParentFolderId(object serverRelativeUrl) + { + return GetParentFolderId((string)serverRelativeUrl); + } + + protected string GetTitleById(object serverRelativeUrl) + { + return ((string)serverRelativeUrl).Split('/').Last(); + } + + + public void Dispose() + { + clientContext.Dispose(); + } + } + + public class SharePointProviderInfoHelper + { + private readonly TimeSpan CacheExpiration; + private readonly ICache FileCache; + private readonly ICache FolderCache; + private readonly ICacheNotify Notify; + + public SharePointProviderInfoHelper(ICacheNotify notify) + { + CacheExpiration = TimeSpan.FromMinutes(1); + FileCache = AscCache.Memory; + FolderCache = AscCache.Memory; + Notify = notify; + + Notify.Subscribe((i) => + { + if (!string.IsNullOrEmpty(i.FileKey)) + { + FileCache.Remove("spointf-" + i.FileKey); + } + if (!string.IsNullOrEmpty(i.FolderKey)) + { + FolderCache.Remove("spointd-" + i.FolderKey); + } + if (string.IsNullOrEmpty(i.FileKey) && string.IsNullOrEmpty(i.FolderKey)) + { + FileCache.Remove(new Regex("^spointf-.*")); + FolderCache.Remove(new Regex("^spointd-.*")); + } + }, CacheNotifyAction.Remove); + } + + public void Invalidate() + { + Notify.Publish(new SharePointProviderCacheItem { }, CacheNotifyAction.Remove); + } + public void PublishFolder(string id) + { + Notify.Publish(new SharePointProviderCacheItem { FolderKey = id }, CacheNotifyAction.Remove); + } + + public void PublishFolder(string id1, string id2) + { + PublishFolder(id1); + PublishFolder(id2); + } + + public void PublishFolder(string id1, string id2, string id3) + { + PublishFolder(id1, id2); + PublishFolder(id3); + } + + public void PublishFile(string fileId, string folderId) + { + Notify.Publish(new SharePointProviderCacheItem { FileKey = fileId, FolderKey = folderId }, CacheNotifyAction.Remove); + } + + public void CreateFolder(string id, string parentFolderId, Folder folder) + { + PublishFolder(parentFolderId); + FolderCache.Insert("spointd-" + id, folder, DateTime.UtcNow.Add(CacheExpiration)); + } + + public Folder GetFolder(string key) + { + return FolderCache.Get(key); + } + + public void AddFolder(string key, Folder folder) + { + FolderCache.Insert(key, folder, DateTime.UtcNow.Add(CacheExpiration)); + } + + public File GetFile(string key) + { + return FileCache.Get(key); + } + + public void AddFile(string key, File file) + { + FileCache.Insert(key, file, DateTime.UtcNow.Add(CacheExpiration)); + } + } + + public static class SharePointProviderInfoExtension + { + public static DIHelper AddSharePointProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddSingleton(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs new file mode 100644 index 0000000000..3161bc1a38 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs @@ -0,0 +1,104 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointSecurityDao : SharePointDaoBase, ISecurityDao + { + public SharePointSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + ProviderInfo.Dispose(); + } + } + + public static class SharePointSecurityDaoExtention + { + public static DIHelper AddSharePointSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs new file mode 100644 index 0000000000..6d4e48dad2 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs @@ -0,0 +1,176 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.SharePoint +{ + internal class SharePointTagDao : SharePointDaoBase, ITagDao + { + public SharePointTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + { + } + + public void Dispose() + { + ProviderInfo.Dispose(); + } + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return new List(); + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return new List(); + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return new List(); + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return new List(); + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + + var folderId = SharePointDaoSelector.ConvertId(parentFolder.ID); + + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(ProviderInfo.GetFolderFolders(folderId).Select(x => ProviderInfo.MakeId(x.ServerRelativeUrl))) + .Concat(ProviderInfo.GetFolderFiles(folderId).Select(x => ProviderInfo.MakeId(x.ServerRelativeUrl))); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return new List(); + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return new List(); + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return new List(); + } + + public IEnumerable SaveTags(Tag tag) + { + return new List(); + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return new List(); + } + } + + public static class SharePointTagDaoExtention + { + public static DIHelper AddSharePointTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} diff --git a/products/ASC.Files/Server/Utils/FileMarker.cs b/products/ASC.Files/Server/Utils/FileMarker.cs index c8a53c75d1..378e6f14bb 100644 --- a/products/ASC.Files/Server/Utils/FileMarker.cs +++ b/products/ASC.Files/Server/Utils/FileMarker.cs @@ -477,7 +477,7 @@ namespace ASC.Web.Files.Utils } else if ((fromCache) > 0) { - news.Add(rootId, (int)fromCache); + news.Add(rootId, fromCache); } }); diff --git a/products/ASC.Files/Server/proto/OneDriveCacheItem.proto b/products/ASC.Files/Server/proto/OneDriveCacheItem.proto new file mode 100644 index 0000000000..db5deb8de0 --- /dev/null +++ b/products/ASC.Files/Server/proto/OneDriveCacheItem.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty.OneDrive; + +message OneDriveCacheItem { + bool ResetAll = 1; + string Key = 2; +} \ No newline at end of file diff --git a/products/ASC.Files/Server/proto/SharePointProviderCacheItem.proto b/products/ASC.Files/Server/proto/SharePointProviderCacheItem.proto new file mode 100644 index 0000000000..59ebcd665d --- /dev/null +++ b/products/ASC.Files/Server/proto/SharePointProviderCacheItem.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package ASC.Files.Thirdparty.SharePoint; + +message SharePointProviderCacheItem { + string FileKey = 1; + string FolderKey = 2; +} \ No newline at end of file From add68d36d479753fe1d2664e86343f3ccf31f96e Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 13 Mar 2020 16:40:58 +0300 Subject: [PATCH 13/30] Files: sharpbox --- ASC.Web.sln | 8 +- products/ASC.Files/Server/ASC.Files.csproj | 1 + .../Core/Thirdparty/ProviderAccountDao.cs | 30 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 5 +- .../Thirdparty/Sharpbox/SharpBoxDaoBase.cs | 579 ++++++++ .../Sharpbox/SharpBoxDaoSelector.cs | 178 +++ .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 655 +++++++++ .../Thirdparty/Sharpbox/SharpBoxFolderDao.cs | 440 ++++++ .../Sharpbox/SharpBoxProviderInfo.cs | 204 +++ .../Sharpbox/SharpBoxSecurityDao.cs | 102 ++ .../Thirdparty/Sharpbox/SharpBoxTagDao.cs | 181 +++ .../AppLimit.CloudComputing.SharpBox.csproj | 27 + .../CloudStorage.cs | 627 +++++++++ .../CloudStorageAsyncFunctions.cs | 210 +++ .../CloudStorageComfortFunctions.cs | 807 +++++++++++ .../CloudStorageLimits.cs | 43 + .../CloudStorageSyncFramework.cs | 250 ++++ .../Common/AsyncObjectRequest.cs | 28 + .../Common/AsyncResultEx.cs | 50 + .../Common/Cache/CachedDictionary.cs | 109 ++ .../Common/Cache/CachedDictionaryBase.cs | 132 ++ .../Common/Extensions/SharpBoxExtensions.cs | 63 + .../Common/IO/PathHelper.cs | 89 ++ .../Common/IO/StreamHelper.cs | 255 ++++ .../Common/Net/HttpException.cs | 21 + .../Common/Net/HttpUtility.cs | 1214 +++++++++++++++++ .../Common/Net/HttpUtilityEx.cs | 160 +++ .../Common/Net/Json/JsonDateTimeConverter.cs | 66 + .../Common/Net/Json/JsonHelper.cs | 73 + .../Common/Net/MimeMapping.cs | 916 +++++++++++++ .../Common/Net/Web/Dav/DavService.cs | 159 +++ .../Common/Net/Web/Ftp/FtpService.cs | 136 ++ .../Common/Net/Web/Http/HttpService.cs | 31 + .../Net/Web/WebRequestExecutedEventArgs.cs | 32 + .../Net/Web/WebRequestExecutingEventArgs.cs | 16 + .../Common/Net/Web/WebRequestManager.cs | 139 ++ .../Net/Web/WebRequestManagerNullProxy.cs | 24 + .../Common/Net/Web/WebRequestMethods.cs | 150 ++ .../Web/WebRequestMultipartFormDataSupport.cs | 100 ++ .../Common/Net/Web/WebRequestService.cs | 521 +++++++ .../Common/Net/Web/WebRequestStream.cs | 131 ++ .../Common/Net/Web/WebRequestStreamHelper.cs | 24 + .../Common/Net/Web/WebResponseStream.cs | 84 ++ .../Net/oAuth/Context/OAuthConsumerContext.cs | 19 + .../Net/oAuth/Context/OAuthServiceContext.cs | 20 + .../Common/Net/oAuth/Impl/OAuthBase.cs | 369 +++++ .../Net/oAuth/Impl/OAuthStreamParser.cs | 40 + .../Net/oAuth/Impl/OAuthUrlGenerator.cs | 85 ++ .../Common/Net/oAuth/OAuthService.cs | 104 ++ .../Common/Net/oAuth/Token/OAuthToken.cs | 32 + .../Common/Net/oAuth20/OAuth20Token.cs | 86 ++ .../Exceptions/ErrorMessages.Designer.cs | 180 +++ .../Exceptions/ErrorMessages.resx | 159 +++ .../Exceptions/SharpBoxErrorCodes.cs | 99 ++ .../Exceptions/SharpBoxException.cs | 94 ++ .../ICloudDirectoryEntry.cs | 73 + .../ICloudFileDataTransfer.cs | 187 +++ .../ICloudFileSystemEntry.cs | 58 + .../ICloudStorageAccessToken.cs | 10 + .../ICloudStorageAsyncInterface.cs | 64 + .../ICloudStorageConfiguration.cs | 30 + .../ICloudStorageProvider.cs | 41 + .../ICloudStoragePublicAPI.cs | 145 ++ .../IResumableUploadSession.cs | 29 + .../Resources/loader.gif | Bin 0 -> 2599 bytes .../StorageProvider/API/GenericHelper.cs | 30 + .../API/GenericStorageProviderFactory.cs | 146 ++ .../API/IStorageProviderService.cs | 178 +++ .../API/IStorageProviderSession.cs | 26 + .../BaseObjects/BaseDirectoryEntry.cs | 170 +++ .../BaseObjects/BaseFileEntry.cs | 116 ++ .../BaseObjects/BaseFileEntryDataTransfer.cs | 163 +++ .../BaseFileEntryDownloadStream.cs | 96 ++ .../BaseObjects/ResumableUploadSession.cs | 75 + .../BoxNet/BoxNetConfiguration.cs | 32 + .../BoxNet/BoxNetStorageProvider.cs | 13 + .../Logic/BoxNetStorageProviderService.cs | 14 + .../StorageProvider/CIFS/CIFSConfiguration.cs | 50 + .../CIFS/CIFSStorageProvider.cs | 12 + .../CIFS/Logic/CIFSStorageProviderService.cs | 292 ++++ .../CIFS/Logic/CIFSStorageProviderSession.cs | 24 + .../StorageProvider/CachedServiceWrapper.cs | 167 +++ .../DropBox/DropBoxAccountInfo.cs | 60 + .../DropBox/DropBoxBaseTokenInformation.cs | 22 + .../DropBox/DropBoxConfiguration.cs | 124 ++ .../DropBox/DropBoxQuotaInfo.cs | 45 + .../DropBox/DropBoxRequestToken.cs | 29 + .../DropBox/DropBoxResourceIDHelpers.cs | 32 + .../DropBox/DropBoxStorageProvider.cs | 40 + .../DropBox/DropBoxStorageProviderTools.cs | 224 +++ .../StorageProvider/DropBox/DropBoxToken.cs | 44 + .../DropBox/Logic/DropBoxRequestParser.cs | 243 ++++ .../Logic/DropBoxStorageProviderService.cs | 721 ++++++++++ .../Logic/DropBoxStorageProviderSession.cs | 31 + .../StorageProvider/Ftp/FtpConfiguration.cs | 50 + .../StorageProvider/Ftp/FtpStorageProvider.cs | 12 + .../Ftp/Logic/FtpStorageProviderService.cs | 353 +++++ .../Ftp/Logic/FtpStorageProviderSession.cs | 24 + .../GenericCurrentCredentials.cs | 28 + .../GenericNetworkCredentials.cs | 45 + .../StorageProvider/GenericStorageProvider.cs | 305 +++++ .../GenericStorageProviderService.cs | 286 ++++ .../GoogleDocsAuthorizationHelper.cs | 75 + .../GoogleDocs/GoogleDocsConfiguration.cs | 62 + .../GoogleDocs/GoogleDocsConstants.cs | 51 + .../GoogleDocs/GoogleDocsRequestToken.cs | 14 + .../GoogleDocs/GoogleDocsResourceHelper.cs | 77 ++ .../GoogleDocs/GoogleDocsStorageProvider.cs | 51 + .../GoogleDocs/GoogleDocsToken.cs | 28 + .../Logic/GoogleDocsStorageProviderService.cs | 649 +++++++++ .../Logic/GoogleDocsStorageProviderSession.cs | 24 + .../GoogleDocs/Logic/GoogleDocsXmlParser.cs | 142 ++ .../SkyDriveAuthorizationHelper.cs | 135 ++ .../SkyDrive/Logic/SkyDriveStorageProvider.cs | 15 + .../Logic/SkyDriveStorageProviderService.cs | 356 +++++ .../Logic/SkyDriveStorageProviderSession.cs | 20 + .../SkyDrive/SkyDriveConfiguration.cs | 22 + .../SkyDrive/SkyDriveConstants.cs | 32 + .../SkyDrive/SkyDriveHelpers.cs | 64 + .../SkyDrive/SkyDriveJsonParser.cs | 167 +++ .../SkyDrive/SkyDriveRequestHelper.cs | 165 +++ .../WebDav/Logic/WebDavRequestParser.cs | 133 ++ .../Logic/WebDavStorageProviderService.cs | 562 ++++++++ .../Logic/WebDavStorageProviderSession.cs | 24 + .../WebDav/WebDavConfiguration.cs | 180 +++ .../WebDav/WebDavStorageProvider.cs | 18 + .../SyncFramework/DirectoryDiff.cs | 209 +++ .../SyncFramework/DirectoryDiffResultItem.cs | 40 + 128 files changed, 18617 insertions(+), 14 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs create mode 100644 products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/AppLimit.CloudComputing.SharpBox.csproj create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorage.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageAsyncFunctions.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageComfortFunctions.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageLimits.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageSyncFramework.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncObjectRequest.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncResultEx.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionary.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionaryBase.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Extensions/SharpBoxExtensions.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/PathHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/StreamHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpException.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtility.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtilityEx.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonDateTimeConverter.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/MimeMapping.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Dav/DavService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Ftp/FtpService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Http/HttpService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutedEventArgs.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutingEventArgs.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManager.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManagerNullProxy.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMethods.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMultipartFormDataSupport.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStream.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStreamHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebResponseStream.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthConsumerContext.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthServiceContext.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthBase.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthStreamParser.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthUrlGenerator.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/OAuthService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Token/OAuthToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth20/OAuth20Token.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.Designer.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.resx create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxErrorCodes.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxException.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudDirectoryEntry.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileDataTransfer.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileSystemEntry.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAccessToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAsyncInterface.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStoragePublicAPI.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/IResumableUploadSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/Resources/loader.gif create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericStorageProviderFactory.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseDirectoryEntry.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntry.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDataTransfer.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDownloadStream.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/ResumableUploadSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/Logic/BoxNetStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CachedServiceWrapper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxAccountInfo.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxBaseTokenInformation.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxQuotaInfo.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxRequestToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxResourceIDHelpers.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProviderTools.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxRequestParser.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericCurrentCredentials.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericNetworkCredentials.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsAuthorizationHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConstants.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsRequestToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsResourceHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsToken.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsXmlParser.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Authorization/SkyDriveAuthorizationHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConstants.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveHelpers.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveJsonParser.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveRequestHelper.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavRequestParser.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderService.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderSession.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavConfiguration.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavStorageProvider.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiff.cs create mode 100644 thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiffResultItem.cs diff --git a/ASC.Web.sln b/ASC.Web.sln index 389a3111cf..4b1b1fe835 100644 --- a/ASC.Web.sln +++ b/ASC.Web.sln @@ -44,10 +44,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Textile", "common\ASC.T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Notify.Textile", "common\ASC.Notify.Textile\ASC.Notify.Textile.csproj", "{DB50E2EF-B4D8-493A-8568-29CAC0DF9062}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASC.ElasticSearch", "common\services\ASC.ElasticSearch\ASC.ElasticSearch.csproj", "{AE1A0E06-6CD4-4E1D-8209-22BBBD6D5652}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.ElasticSearch", "common\services\ASC.ElasticSearch\ASC.ElasticSearch.csproj", "{AE1A0E06-6CD4-4E1D-8209-22BBBD6D5652}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Files", "products\ASC.Files\Server\ASC.Files.csproj", "{77BA2F61-6155-4283-BB39-F8E42F46A0B0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppLimit.CloudComputing.SharpBox", "thirdparty\AppLimit.CloudComputing.SharpBox\AppLimit.CloudComputing.SharpBox.csproj", "{5B53855C-4347-4402-B750-76C6295A35D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -138,6 +140,10 @@ Global {77BA2F61-6155-4283-BB39-F8E42F46A0B0}.Debug|Any CPU.Build.0 = Debug|Any CPU {77BA2F61-6155-4283-BB39-F8E42F46A0B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {77BA2F61-6155-4283-BB39-F8E42F46A0B0}.Release|Any CPU.Build.0 = Release|Any CPU + {5B53855C-4347-4402-B750-76C6295A35D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B53855C-4347-4402-B750-76C6295A35D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B53855C-4347-4402-B750-76C6295A35D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B53855C-4347-4402-B750-76C6295A35D3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index 524082b811..477d868e38 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -49,6 +49,7 @@ + diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index 29c5068f14..f06026344e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -45,6 +45,7 @@ using ASC.Files.Thirdparty.Dropbox; using ASC.Files.Thirdparty.GoogleDrive; using ASC.Files.Thirdparty.OneDrive; using ASC.Files.Thirdparty.SharePoint; +using ASC.Files.Thirdparty.Sharpbox; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; @@ -376,6 +377,7 @@ namespace ASC.Files.Thirdparty var owner = input.UserId; var folderType = input.FolderType; var createOn = TenantUtil.DateTimeFromUtc(input.CreateOn); + var authData = new AuthData(input.Url, input.UserName, DecryptPassword(input.Password), token); if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null"); @@ -408,8 +410,6 @@ namespace ASC.Files.Thirdparty if (key == ProviderTypes.SharePoint) { - var authData = new AuthData(input.Url, input.UserName, DecryptPassword(input.Password), token); - if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password)) throw new ArgumentNullException("password", "Password can't be null"); @@ -452,16 +452,23 @@ namespace ASC.Files.Thirdparty return od; } - //return new SharpBoxProviderInfo( - // id, - // key.ToString(), - // providerTitle, - // new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token), - // owner, - // folderType, - // createOn); + if (string.IsNullOrEmpty(input.Provider)) + throw new ArgumentNullException("providerKey"); + if (string.IsNullOrEmpty(authData.Token) && string.IsNullOrEmpty(authData.Password)) + throw new ArgumentNullException("token", "Both token and password can't be null"); + if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password) && string.IsNullOrEmpty(authData.Token)) + throw new ArgumentNullException("password", "Password can't be null"); - return null; + var sharpBoxProviderInfo = ServiceProvider.GetService(); + sharpBoxProviderInfo.ID = id; + sharpBoxProviderInfo.CustomerTitle = providerTitle; + sharpBoxProviderInfo.Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + sharpBoxProviderInfo.ProviderKey = input.Provider; + sharpBoxProviderInfo.RootFolderType = folderType; + sharpBoxProviderInfo.CreateOn = createOn; + sharpBoxProviderInfo.AuthData = authData; + + return sharpBoxProviderInfo; } private AuthData GetEncodedAccesToken(AuthData authData, ProviderTypes provider) @@ -583,6 +590,7 @@ namespace ASC.Files.Thirdparty //services.TryAddScoped(); return services + .AddSharpBoxProviderInfoService() .AddSharePointProviderInfoService() .AddOneDriveProviderInfoService() .AddGoogleDriveProviderInfoService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index 230c0c62d7..8778272c7a 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -38,6 +38,7 @@ using ASC.Files.Thirdparty.Dropbox; using ASC.Files.Thirdparty.GoogleDrive; using ASC.Files.Thirdparty.OneDrive; using ASC.Files.Thirdparty.SharePoint; +using ASC.Files.Thirdparty.Sharpbox; using ASC.Web.Files.Utils; using ASC.Web.Studio.Core; @@ -63,9 +64,8 @@ namespace ASC.Files.Thirdparty.ProviderDao FileConverter = fileConverter; Selectors = new List { - //Fill in selectors - //Selectors.Add(new SharpBoxDaoSelector()); + ServiceProvider.GetService(), ServiceProvider.GetService(), ServiceProvider.GetService(), ServiceProvider.GetService(), @@ -267,6 +267,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderDaoBaseService(this DIHelper services) { return services + .AddSharpBoxDaoSelectorService() .AddSharePointSelectorService() .AddOneDriveSelectorService() .AddGoogleDriveSelectorService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs new file mode 100644 index 0000000000..4f37a724bc --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs @@ -0,0 +1,579 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using AppLimit.CloudComputing.SharpBox; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Security.Cryptography; +using ASC.Web.Files.Classes; +using ASC.Web.Studio.Core; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal abstract class SharpBoxDaoBase : IDisposable + { + protected class ErrorEntry : ICloudDirectoryEntry + { + public ErrorEntry(Exception e, object id) + { + if (e != null) Error = e.Message; + + Id = string.IsNullOrEmpty((id ?? "").ToString()) ? "/" : (id ?? "").ToString(); + } + + public string Error { get; set; } + + public string Name + { + get { return "/"; } + } + + public string Id { get; private set; } + + public long Length + { + get { return 0; } + } + + public DateTime Modified + { + get { return DateTime.UtcNow; } + } + + public string ParentID + { + get { return ""; } + set { } + } + + public ICloudDirectoryEntry Parent + { + get { return null; } + set { } + } + + public ICloudFileDataTransfer GetDataTransferAccessor() + { + return null; + } + + public string GetPropertyValue(string key) + { + return null; + } + + private readonly List _entries = new List(0); + + public IEnumerator GetEnumerator() + { + return _entries.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public ICloudFileSystemEntry GetChild(string name) + { + return null; + } + + public ICloudFileSystemEntry GetChild(string name, bool bThrowException) + { + if (bThrowException) throw new ArgumentNullException(name); + return null; + } + + public ICloudFileSystemEntry GetChild(string idOrName, bool bThrowException, bool firstByNameIfNotFound) + { + if (bThrowException) throw new ArgumentNullException(idOrName); + return null; + } + + public ICloudFileSystemEntry GetChild(int idx) + { + return null; + } + + public int Count + { + get { return 0; } + } + + public nChildState HasChildrens + { + get { return nChildState.HasNoChilds; } + } + } + + public int TenantID { get; private set; } + + public SharpBoxDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor) + { + TenantID = tenantManager.GetCurrentTenant().TenantId; + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + SetupInfo = setupInfo; + Log = monitor.CurrentValue; + } + + public void Init(SharpBoxDaoSelector.SharpBoxInfo sharpBoxInfo, SharpBoxDaoSelector sharpBoxDaoSelector) + { + SharpBoxProviderInfo = sharpBoxInfo.SharpBoxProviderInfo; + PathPrefix = sharpBoxInfo.PathPrefix; + SharpBoxDaoSelector = sharpBoxDaoSelector; + } + + public void Dispose() + { + SharpBoxProviderInfo.Dispose(); + } + + protected string MappingID(string id, bool saveIfNotExist) + { + if (id == null) return null; + + string result; + if (id.ToString().StartsWith("sbox")) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + + return result; + } + + protected string MappingID(string id) + { + return MappingID(id, false); + } + + protected void UpdatePathInDB(string oldValue, string newValue) + { + if (oldValue.Equals(newValue)) return; + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var oldIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(oldValue)) + .Select(r => r.Id) + .ToList(); + + foreach (var oldID in oldIDs) + { + var oldHashID = MappingID(oldID); + var newID = oldID.Replace(oldValue, newValue); + var newHashID = MappingID(newID); + + var mappingForUpdate = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.HashId == oldHashID) + .ToList(); + + foreach (var m in mappingForUpdate) + { + m.Id = newID; + m.HashId = newHashID; + } + + FilesDbContext.SaveChanges(); + + var securityForUpdate = Query(FilesDbContext.Security) + .Where(r => r.EntryId == oldHashID) + .ToList(); + + foreach (var s in securityForUpdate) + { + s.EntryId = newHashID; + } + + FilesDbContext.SaveChanges(); + + var linkForUpdate = Query(FilesDbContext.TagLink) + .Where(r => r.EntryId == oldHashID) + .ToList(); + + foreach (var l in linkForUpdate) + { + l.EntryId = newHashID; + } + + FilesDbContext.SaveChanges(); + } + + tx.Commit(); + } + } + + protected SharpBoxDaoSelector SharpBoxDaoSelector; + public SharpBoxProviderInfo SharpBoxProviderInfo { get; set; } + public string PathPrefix { get; private set; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantUtil TenantUtil { get; } + public FilesDbContext FilesDbContext { get; } + public SetupInfo SetupInfo { get; } + public ILog Log { get; } + + protected IQueryable Query(DbSet set) where T : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + protected string GetTenantColumnName(string table) + { + const string tenant = "tenant_id"; + if (!table.Contains(" ")) return tenant; + return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant; + } + + protected string MakePath(object entryId) + { + return string.Format("/{0}", Convert.ToString(entryId, CultureInfo.InvariantCulture).Trim('/')); + } + + protected string MakeId(ICloudFileSystemEntry entry) + { + var path = string.Empty; + if (entry != null && !(entry is ErrorEntry)) + { + try + { + path = SharpBoxProviderInfo.Storage.GetFileSystemObjectPath(entry); + } + catch (Exception ex) + { + Log.Error("Sharpbox makeId error", ex); + } + } + else if (entry != null) + { + path = entry.Id; + } + + return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "/" ? "" : ("-" + path.Replace('/', '|'))); + } + + protected string MakeTitle(ICloudFileSystemEntry fsEntry) + { + if (fsEntry is ICloudDirectoryEntry && IsRoot(fsEntry as ICloudDirectoryEntry)) + { + return SharpBoxProviderInfo.CustomerTitle; + } + + return Global.ReplaceInvalidCharsAndTruncate(fsEntry.Name); + } + + protected string PathParent(string path) + { + if (!string.IsNullOrEmpty(path)) + { + var index = path.TrimEnd('/').LastIndexOf('/'); + if (index != -1) + { + //Cut to it + return path.Substring(0, index); + } + } + return path; + } + + protected Folder ToFolder(ICloudDirectoryEntry fsEntry) + { + if (fsEntry == null) return null; + if (fsEntry is ErrorEntry) + { + //Return error entry + return ToErrorFolder(fsEntry as ErrorEntry); + } + + //var childFoldersCount = fsEntry.OfType().Count();//NOTE: Removed due to performance isssues + var isRoot = IsRoot(fsEntry); + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(fsEntry); + folder.ParentFolderID = isRoot ? null : MakeId(fsEntry.Parent); + folder.CreateBy = SharpBoxProviderInfo.Owner; + folder.CreateOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified; + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = SharpBoxProviderInfo.Owner; + folder.ModifiedOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified; + folder.ProviderId = SharpBoxProviderInfo.ID; + folder.ProviderKey = SharpBoxProviderInfo.ProviderKey; + folder.RootFolderCreator = SharpBoxProviderInfo.Owner; + folder.RootFolderId = MakeId(RootFolder()); + folder.RootFolderType = SharpBoxProviderInfo.RootFolderType; + + folder.Shareable = false; + folder.Title = MakeTitle(fsEntry); + folder.TotalFiles = 0; /*fsEntry.Count - childFoldersCount NOTE: Removed due to performance isssues*/ + folder.TotalSubFolders = 0; /*childFoldersCount NOTE: Removed due to performance isssues*/ + + if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) + folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); + + if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc) + folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn); + + return folder; + } + + private static bool IsRoot(ICloudDirectoryEntry entry) + { + if (entry != null && entry.Name != null) + return string.IsNullOrEmpty(entry.Name.Trim('/')); + return false; + } + + private File ToErrorFile(ErrorEntry fsEntry) + { + if (fsEntry == null) return null; + + var file = ServiceProvider.GetService>(); + + file.ID = MakeId(fsEntry); + file.CreateBy = SharpBoxProviderInfo.Owner; + file.CreateOn = fsEntry.Modified; + file.ModifiedBy = SharpBoxProviderInfo.Owner; + file.ModifiedOn = fsEntry.Modified; + file.ProviderId = SharpBoxProviderInfo.ID; + file.ProviderKey = SharpBoxProviderInfo.ProviderKey; + file.RootFolderCreator = SharpBoxProviderInfo.Owner; + file.RootFolderId = MakeId(null); + file.RootFolderType = SharpBoxProviderInfo.RootFolderType; + file.Title = MakeTitle(fsEntry); + file.Error = fsEntry.Error; + + return file; + } + + private Folder ToErrorFolder(ErrorEntry fsEntry) + { + if (fsEntry == null) return null; + var folder = ServiceProvider.GetService>(); + + folder.ID = MakeId(fsEntry); + folder.ParentFolderID = null; + folder.CreateBy = SharpBoxProviderInfo.Owner; + folder.CreateOn = fsEntry.Modified; + folder.FolderType = FolderType.DEFAULT; + folder.ModifiedBy = SharpBoxProviderInfo.Owner; + folder.ModifiedOn = fsEntry.Modified; + folder.ProviderId = SharpBoxProviderInfo.ID; + folder.ProviderKey = SharpBoxProviderInfo.ProviderKey; + folder.RootFolderCreator = SharpBoxProviderInfo.Owner; + folder.RootFolderId = MakeId(null); + folder.RootFolderType = SharpBoxProviderInfo.RootFolderType; + folder.Shareable = false; + folder.Title = MakeTitle(fsEntry); + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + folder.Error = fsEntry.Error; + + return folder; + } + + protected File ToFile(ICloudFileSystemEntry fsEntry) + { + if (fsEntry == null) return null; + + if (fsEntry is ErrorEntry) + { + //Return error entry + return ToErrorFile(fsEntry as ErrorEntry); + } + + var file = ServiceProvider.GetService>(); + + + file.ID = MakeId(fsEntry); + file.Access = FileShare.None; + file.ContentLength = fsEntry.Length; + file.CreateBy = SharpBoxProviderInfo.Owner; + file.CreateOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified; + file.FileStatus = FileStatus.None; + file.FolderID = MakeId(fsEntry.Parent); + file.ModifiedBy = SharpBoxProviderInfo.Owner; + file.ModifiedOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified; + file.NativeAccessor = fsEntry; + file.ProviderId = SharpBoxProviderInfo.ID; + file.ProviderKey = SharpBoxProviderInfo.ProviderKey; + file.Title = MakeTitle(fsEntry); + file.RootFolderId = MakeId(RootFolder()); + file.RootFolderType = SharpBoxProviderInfo.RootFolderType; + file.RootFolderCreator = SharpBoxProviderInfo.Owner; + file.Shared = false; + file.Version = 1; + + return file; + } + + protected ICloudDirectoryEntry RootFolder() + { + return SharpBoxProviderInfo.Storage.GetRoot(); + } + + protected ICloudDirectoryEntry GetFolderById(object folderId) + { + try + { + var path = MakePath(folderId); + return path == "/" + ? RootFolder() + : SharpBoxProviderInfo.Storage.GetFolder(path); + } + catch (SharpBoxException sharpBoxException) + { + if (sharpBoxException.ErrorCode == SharpBoxErrorCodes.ErrorFileNotFound) + { + return null; + } + return new ErrorEntry(sharpBoxException, folderId); + } + catch (Exception ex) + { + return new ErrorEntry(ex, folderId); + } + } + + protected ICloudFileSystemEntry GetFileById(object fileId) + { + try + { + return SharpBoxProviderInfo.Storage.GetFile(MakePath(fileId), null); + } + catch (SharpBoxException sharpBoxException) + { + if (sharpBoxException.ErrorCode == SharpBoxErrorCodes.ErrorFileNotFound) + { + return null; + } + return new ErrorEntry(sharpBoxException, fileId); + } + catch (Exception ex) + { + return new ErrorEntry(ex, fileId); + } + } + + protected IEnumerable GetFolderFiles(object folderId) + { + return GetFolderFiles(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId))); + } + + protected IEnumerable GetFolderSubfolders(object folderId) + { + return GetFolderSubfolders(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId))); + } + + protected IEnumerable GetFolderFiles(ICloudDirectoryEntry folder) + { + return folder.Where(x => !(x is ICloudDirectoryEntry)); + } + + protected IEnumerable GetFolderSubfolders(ICloudDirectoryEntry folder) + { + return folder.Where(x => (x is ICloudDirectoryEntry)); + } + + protected string GetAvailableTitle(string requestTitle, ICloudDirectoryEntry parentFolder, Func isExist) + { + if (!isExist(requestTitle, parentFolder)) return requestTitle; + + var re = new Regex(@"( \(((?[0-9])+)\)(\.[^\.]*)?)$"); + var match = re.Match(requestTitle); + + if (!match.Success) + { + var insertIndex = requestTitle.Length; + if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1) + { + insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture); + } + requestTitle = requestTitle.Insert(insertIndex, " (1)"); + } + + while (isExist(requestTitle, parentFolder)) + { + requestTitle = re.Replace(requestTitle, MatchEvaluator); + } + return requestTitle; + } + + private static string MatchEvaluator(Match match) + { + var index = Convert.ToInt32(match.Groups[2].Value); + var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); + return string.Format(" ({0}){1}", index + 1, staticText); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs new file mode 100644 index 0000000000..e88c4a3c3f --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs @@ -0,0 +1,178 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Text.RegularExpressions; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Security; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxDaoSelector : RegexDaoSelectorBase + { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } + + internal class SharpBoxInfo + { + public SharpBoxProviderInfo SharpBoxProviderInfo { get; set; } + + public string Path { get; set; } + public string PathPrefix { get; set; } + } + + public SharpBoxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) + : base(new Regex(@"^sbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + { + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + } + + public override IFileDao GetFileDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override IFolderDao GetFolderDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ITagDao GetTagDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override ISecurityDao GetSecurityDao(string id) + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + public override string ConvertId(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException("Id is not a sharpbox id"); + } + return base.ConvertId(null); + } + + private SharpBoxInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new SharpBoxInfo + { + Path = match.Groups["path"].Value, + SharpBoxProviderInfo = providerInfo, + PathPrefix = "sbox-" + match.Groups["id"].Value + }; + } + throw new ArgumentException("Id is not a sharpbox id"); + } + + public override string GetIdCode(string id) + { + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + return base.GetIdCode(id); + } + + private SharpBoxProviderInfo GetProviderInfo(int linkId) + { + SharpBoxProviderInfo info; + + var dbDao = DaoFactory.ProviderDao; + + try + { + info = (SharpBoxProviderInfo)dbDao.GetProviderInfo(linkId); + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + return info; + } + + public void RenameProvider(SharpBoxProviderInfo sharpBoxProviderInfo, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(sharpBoxProviderInfo.ID, newTitle, null, sharpBoxProviderInfo.RootFolderType); + sharpBoxProviderInfo.UpdateTitle(newTitle); //This will update cached version too + } + } + + public static class SharpBoxDaoSelectorExtention + { + public static DIHelper AddSharpBoxDaoSelectorService(this DIHelper services) + { + services.TryAddScoped(); + + return services + .AddSharpBoxSecurityDaoService() + .AddSharpBoxTagDaoService() + .AddSharpBoxFolderDaoService() + .AddSharpBoxFileDaoService(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs new file mode 100644 index 0000000000..05e21b4817 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -0,0 +1,655 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Security; + +using AppLimit.CloudComputing.SharpBox; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Core.Files; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Studio.Core; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao + { + public SharpBoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + { + } + + public void InvalidateCache(string fileId) + { + SharpBoxProviderInfo.InvalidateStorage(); + } + + public File GetFile(string fileId) + { + return GetFile(fileId, 1); + } + + public File GetFile(string fileId, int fileVersion) + { + return ToFile(GetFileById(fileId)); + } + + public File GetFile(string parentId, string title) + { + return ToFile(GetFolderFiles(parentId).FirstOrDefault(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase))); + } + + public File GetFileStable(string fileId, int fileVersion) + { + return ToFile(GetFileById(fileId)); + } + + public List> GetFileHistory(string fileId) + { + return new List> { GetFile(fileId) }; + } + + public List> GetFiles(string[] fileIds) + { + return fileIds.Select(fileId => ToFile(GetFileById(fileId))).ToList(); + } + + public List> GetFilesForShare(string[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + if (fileIds == null || fileIds.Length == 0 || filterType == FilterType.FoldersOnly) return new List>(); + + var files = GetFiles(fileIds).AsEnumerable(); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return files.ToList(); + } + + public List GetFiles(string parentId) + { + var folder = GetFolderById(parentId).AsEnumerable(); + + return folder + .Where(x => !(x is ICloudDirectoryEntry)) + .Select(x => MakeId(x)).ToList(); + } + + public List> GetFiles(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false) + { + if (filterType == FilterType.FoldersOnly) return new List>(); + + //Get only files + var files = GetFolderById(parentId).Where(x => !(x is ICloudDirectoryEntry)).Select(ToFile); + + //Filter + if (subjectID != Guid.Empty) + { + files = files.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + switch (filterType) + { + case FilterType.FoldersOnly: + return new List>(); + case FilterType.DocumentsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Document); + break; + case FilterType.PresentationsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Presentation); + break; + case FilterType.SpreadsheetsOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Spreadsheet); + break; + case FilterType.ImagesOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Image); + break; + case FilterType.ArchiveOnly: + files = files.Where(x => FileUtility.GetFileTypeByFileName(x.Title) == FileType.Archive); + break; + case FilterType.MediaOnly: + files = files.Where(x => + { + FileType fileType; + return (fileType = FileUtility.GetFileTypeByFileName(x.Title)) == FileType.Audio || fileType == FileType.Video; + }); + break; + case FilterType.ByExtension: + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => FileUtility.GetFileExtension(x.Title).Contains(searchText)); + break; + } + + if (!string.IsNullOrEmpty(searchText)) + files = files.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateBy) : files.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + files = orderBy.IsAsc ? files.OrderBy(x => x.ModifiedOn) : files.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + files = orderBy.IsAsc ? files.OrderBy(x => x.CreateOn) : files.OrderByDescending(x => x.CreateOn); + break; + default: + files = orderBy.IsAsc ? files.OrderBy(x => x.Title) : files.OrderByDescending(x => x.Title); + break; + } + + return files.ToList(); + } + + public Stream GetFileStream(File file, long offset) + { + var fileToDownload = GetFileById(file.ID); + + if (fileToDownload == null) + throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + if (fileToDownload is ErrorEntry) + throw new Exception(((ErrorEntry)fileToDownload).Error); + + var fileStream = fileToDownload.GetDataTransferAccessor().GetDownloadStream(); + + if (fileStream != null && offset > 0) + { + if (!fileStream.CanSeek) + { + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + + fileStream.CopyTo(tempBuffer); + tempBuffer.Flush(); + tempBuffer.Seek(offset, SeekOrigin.Begin); + + fileStream.Dispose(); + return tempBuffer; + } + + fileStream.Seek(offset, SeekOrigin.Begin); + } + + return fileStream; + } + + public Uri GetPreSignedUri(File file, TimeSpan expires) + { + throw new NotSupportedException(); + } + + public bool IsSupportedPreSignedUri(File file) + { + return false; + } + + public Stream GetFileStream(File file) + { + return GetFileStream(file, 0); + } + + public File SaveFile(File file, Stream fileStream) + { + if (fileStream == null) throw new ArgumentNullException("fileStream"); + ICloudFileSystemEntry entry = null; + if (file.ID != null) + { + entry = SharpBoxProviderInfo.Storage.GetFile(MakePath(file.ID), null); + } + else if (file.FolderID != null) + { + var folder = GetFolderById(file.FolderID); + file.Title = GetAvailableTitle(file.Title, folder, IsExist); + entry = SharpBoxProviderInfo.Storage.CreateFile(folder, file.Title); + } + + if (entry == null) + { + return null; + } + + try + { + entry.GetDataTransferAccessor().Transfer(fileStream.GetBuffered(), nTransferDirection.nUpload); + } + catch (SharpBoxException e) + { + var webException = (WebException)e.InnerException; + if (webException != null) + { + var response = ((HttpWebResponse)webException.Response); + if (response != null) + { + if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) + { + throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); + } + } + throw; + } + } + + if (file.ID != null && !entry.Name.Equals(file.Title)) + { + file.Title = GetAvailableTitle(file.Title, entry.Parent, IsExist); + SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, file.Title); + } + + return ToFile(entry); + } + + public File ReplaceFileVersion(File file, Stream fileStream) + { + return SaveFile(file, fileStream); + } + + public void DeleteFile(string fileId) + { + var file = GetFileById(fileId); + if (file == null) return; + var id = MakeId(file); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(file is ErrorEntry)) + SharpBoxProviderInfo.Storage.DeleteFileSystemEntry(file); + } + + public bool IsExist(string title, object folderId) + { + var folder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId)); + return IsExist(title, folder); + } + + public bool IsExist(string title, ICloudDirectoryEntry folder) + { + try + { + return SharpBoxProviderInfo.Storage.GetFileSystemObject(title, folder) != null; + } + catch (ArgumentException) + { + throw; + } + catch (Exception) + { + } + return false; + } + + public string MoveFile(string fileId, string toFolderId) + { + var entry = GetFileById(fileId); + var folder = GetFolderById(toFolderId); + + var oldFileId = MakeId(entry); + + if (!SharpBoxProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) + throw new Exception("Error while moving"); + + var newFileId = MakeId(entry); + + UpdatePathInDB(oldFileId, newFileId); + + return newFileId; + } + + public File CopyFile(string fileId, string toFolderId) + { + var file = GetFileById(fileId); + if (!SharpBoxProviderInfo.Storage.CopyFileSystemEntry(MakePath(fileId), MakePath(toFolderId))) + throw new Exception("Error while copying"); + return ToFile(GetFolderById(toFolderId).FirstOrDefault(x => x.Name == file.Name)); + } + + public string FileRename(File file, string newTitle) + { + var entry = GetFileById(file.ID); + + if (entry == null) + throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); + + var oldFileId = MakeId(entry); + var newFileId = oldFileId; + + var folder = GetFolderById(file.FolderID); + newTitle = GetAvailableTitle(newTitle, folder, IsExist); + + if (SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) + { + //File data must be already updated by provider + //We can't search google files by title because root can have multiple folders with the same name + //var newFile = SharpBoxProviderInfo.Storage.GetFileSystemObject(newTitle, file.Parent); + newFileId = MakeId(entry); + } + + UpdatePathInDB(oldFileId, newFileId); + + return newFileId; + } + + public string UpdateComment(string fileId, int fileVersion, string comment) + { + return string.Empty; + } + + public void CompleteVersion(string fileId, int fileVersion) + { + } + + public void ContinueVersion(string fileId, int fileVersion) + { + } + + public bool UseTrashForRemove(File file) + { + return false; + } + + #region chunking + + public ChunkedUploadSession CreateUploadSession(File file, long contentLength) + { + if (SetupInfo.ChunkUploadSize > contentLength) + return new ChunkedUploadSession(MakeId(file), contentLength) { UseChunks = false }; + + var uploadSession = new ChunkedUploadSession(file, contentLength); + + var isNewFile = false; + + ICloudFileSystemEntry sharpboxFile; + if (file.ID != null) + { + sharpboxFile = GetFileById(file.ID); + } + else + { + var folder = GetFolderById(file.FolderID); + sharpboxFile = SharpBoxProviderInfo.Storage.CreateFile(folder, GetAvailableTitle(file.Title, folder, IsExist)); + isNewFile = true; + } + + var sharpboxSession = sharpboxFile.GetDataTransferAccessor().CreateResumableSession(contentLength); + if (sharpboxSession != null) + { + uploadSession.Items["SharpboxSession"] = sharpboxSession; + uploadSession.Items["IsNewFile"] = isNewFile; + } + else + { + uploadSession.Items["TempPath"] = Path.GetTempFileName(); + } + + uploadSession.File = MakeId(uploadSession.File); + return uploadSession; + } + + public void UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength) + { + if (!uploadSession.UseChunks) + { + if (uploadSession.BytesTotal == 0) + uploadSession.BytesTotal = chunkLength; + + uploadSession.File = SaveFile(uploadSession.File, stream); + uploadSession.BytesUploaded = chunkLength; + return; + } + + if (uploadSession.Items.ContainsKey("SharpboxSession")) + { + var sharpboxSession = + uploadSession.GetItemOrDefault("SharpboxSession"); + + var isNewFile = uploadSession.Items.ContainsKey("IsNewFile") && uploadSession.GetItemOrDefault("IsNewFile"); + var sharpboxFile = + isNewFile + ? SharpBoxProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) + : GetFileById(sharpboxSession.FileId); + + sharpboxFile.GetDataTransferAccessor().Transfer(sharpboxSession, stream, chunkLength); + } + else + { + var tempPath = uploadSession.GetItemOrDefault("TempPath"); + using (var fs = new FileStream(tempPath, FileMode.Append)) + { + stream.CopyTo(fs); + } + } + + uploadSession.BytesUploaded += chunkLength; + + if (uploadSession.BytesUploaded == uploadSession.BytesTotal) + { + uploadSession.File = FinalizeUploadSession(uploadSession); + } + else + { + uploadSession.File = MakeId(uploadSession.File); + } + } + + public File FinalizeUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("SharpboxSession")) + { + var sharpboxSession = + uploadSession.GetItemOrDefault("SharpboxSession"); + return ToFile(GetFileById(sharpboxSession.FileId)); + } + + using (var fs = new FileStream(uploadSession.GetItemOrDefault("TempPath"), FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) + { + return SaveFile(uploadSession.File, fs); + } + } + + public void AbortUploadSession(ChunkedUploadSession uploadSession) + { + if (uploadSession.Items.ContainsKey("SharpboxSession")) + { + var sharpboxSession = + uploadSession.GetItemOrDefault("SharpboxSession"); + + var isNewFile = uploadSession.Items.ContainsKey("IsNewFile") && uploadSession.GetItemOrDefault("IsNewFile"); + var sharpboxFile = + isNewFile + ? SharpBoxProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) + : GetFileById(sharpboxSession.FileId); + sharpboxFile.GetDataTransferAccessor().AbortResumableSession(sharpboxSession); + } + else if (uploadSession.Items.ContainsKey("TempPath")) + { + System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + } + } + + private File MakeId(File file) + { + if (file.ID != null) + file.ID = PathPrefix + "-" + file.ID; + + if (file.FolderID != null) + file.FolderID = PathPrefix + "-" + file.FolderID; + + return file; + } + + #endregion + + #region Only in TMFileDao + + public void ReassignFiles(string[] fileIds, Guid newOwnerId) + { + } + + public List> GetFiles(string[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent) + { + return new List>(); + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public bool IsExistOnStorage(File file) + { + return true; + } + + public void SaveEditHistory(File file, string changes, Stream differenceStream) + { + //Do nothing + } + + public List GetEditHistory(DocumentServiceHelper documentServiceHelper, string fileId, int fileVersion) + { + return null; + } + + public Stream GetDifferenceStream(File file) + { + return null; + } + + public bool ContainChanges(string fileId, int fileVersion) + { + return false; + } + + public string GetUniqFilePath(File file, string fileTitle) + { + throw new NotImplementedException(); + } + + #endregion + } + + public static class SharpBoxFileDaoExtention + { + public static DIHelper AddSharpBoxFileDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs new file mode 100644 index 0000000000..0365b370e5 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs @@ -0,0 +1,440 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Security; +using System.Threading; + +using AppLimit.CloudComputing.SharpBox; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Resources; +using ASC.Web.Studio.Core; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxFolderDao : SharpBoxDaoBase, IFolderDao + { + public SharpBoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + { + } + + public Folder GetFolder(string folderId) + { + return ToFolder(GetFolderById(folderId)); + } + + public Folder GetFolder(string title, string parentId) + { + var parentFolder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(parentId)); + return ToFolder(parentFolder.OfType().FirstOrDefault(x => x.Name.Equals(title, StringComparison.OrdinalIgnoreCase))); + } + + public Folder GetRootFolder(string folderId) + { + return ToFolder(RootFolder()); + } + + public Folder GetRootFolderByFile(string fileId) + { + return ToFolder(RootFolder()); + } + + public List> GetFolders(string parentId) + { + var parentFolder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(parentId)); + return parentFolder.OfType().Select(ToFolder).ToList(); + } + + public List> GetFolders(string parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = GetFolders(parentId).AsEnumerable(); //TODO:!!! + + //Filter + if (subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); + + switch (orderBy.SortedBy) + { + case SortedByType.Author: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateBy) : folders.OrderByDescending(x => x.CreateBy); + break; + case SortedByType.AZ: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + case SortedByType.DateAndTime: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.ModifiedOn) : folders.OrderByDescending(x => x.ModifiedOn); + break; + case SortedByType.DateAndTimeCreation: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.CreateOn) : folders.OrderByDescending(x => x.CreateOn); + break; + default: + folders = orderBy.IsAsc ? folders.OrderBy(x => x.Title) : folders.OrderByDescending(x => x.Title); + break; + } + + return folders.ToList(); + } + + public List> GetFolders(string[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true) + { + if (filterType == FilterType.FilesOnly || filterType == FilterType.ByExtension + || filterType == FilterType.DocumentsOnly || filterType == FilterType.ImagesOnly + || filterType == FilterType.PresentationsOnly || filterType == FilterType.SpreadsheetsOnly + || filterType == FilterType.ArchiveOnly || filterType == FilterType.MediaOnly) + return new List>(); + + var folders = folderIds.Select(GetFolder); + + if (subjectID.HasValue && subjectID != Guid.Empty) + { + folders = folders.Where(x => subjectGroup + ? UserManager.IsUserInGroup(x.CreateBy, subjectID.Value) + : x.CreateBy == subjectID); + } + + if (!string.IsNullOrEmpty(searchText)) + folders = folders.Where(x => x.Title.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) != -1); + + return folders.ToList(); + } + + public List> GetParentFolders(string folderId) + { + var path = new List>(); + var folder = GetFolderById(folderId); + if (folder != null) + { + do + { + path.Add(ToFolder(folder)); + } while ((folder = folder.Parent) != null); + } + path.Reverse(); + return path; + } + + public string SaveFolder(Folder folder) + { + try + { + if (folder.ID != null) + { + //Create with id + var savedfolder = SharpBoxProviderInfo.Storage.CreateFolder(MakePath(folder.ID)); + return MakeId(savedfolder); + } + if (folder.ParentFolderID != null) + { + var parentFolder = GetFolderById(folder.ParentFolderID); + + folder.Title = GetAvailableTitle(folder.Title, parentFolder, IsExist); + + var newFolder = SharpBoxProviderInfo.Storage.CreateFolder(folder.Title, parentFolder); + return MakeId(newFolder); + } + } + catch (SharpBoxException e) + { + var webException = (WebException)e.InnerException; + if (webException != null) + { + var response = ((HttpWebResponse)webException.Response); + if (response != null) + { + if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) + { + throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); + } + } + throw; + } + } + return null; + } + + public void DeleteFolder(string folderId) + { + var folder = GetFolderById(folderId); + var id = MakeId(folder); + + using (var tx = FilesDbContext.Database.BeginTransaction()) + { + var hashIDs = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => r.Id.StartsWith(id)) + .Select(r => r.HashId) + .ToList(); + + var link = Query(FilesDbContext.TagLink) + .Where(r => hashIDs.Any(h => h == r.EntryId)) + .ToList(); + + FilesDbContext.TagLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + + var tagsToRemove = Query(FilesDbContext.Tag) + .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); + + FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var securityToDelete = Query(FilesDbContext.Security) + .Where(r => hashIDs.Any(h => h == r.EntryId)); + + FilesDbContext.Security.RemoveRange(securityToDelete); + FilesDbContext.SaveChanges(); + + var mappingToDelete = Query(FilesDbContext.ThirdpartyIdMapping) + .Where(r => hashIDs.Any(h => h == r.HashId)); + + FilesDbContext.ThirdpartyIdMapping.RemoveRange(mappingToDelete); + FilesDbContext.SaveChanges(); + + tx.Commit(); + } + + if (!(folder is ErrorEntry)) + SharpBoxProviderInfo.Storage.DeleteFileSystemEntry(folder); + } + + public bool IsExist(string title, ICloudDirectoryEntry folder) + { + try + { + return SharpBoxProviderInfo.Storage.GetFileSystemObject(title, folder) != null; + } + catch (ArgumentException) + { + throw; + } + catch (Exception) + { + + } + return false; + } + + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var entry = GetFolderById(folderId); + var folder = GetFolderById(toFolderId); + + var oldFolderId = MakeId(entry); + + if (!SharpBoxProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) + throw new Exception("Error while moving"); + + var newFolderId = MakeId(entry); + + UpdatePathInDB(oldFolderId, newFolderId); + + return newFolderId; + } + + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) + { + var folder = GetFolderById(folderId); + if (!SharpBoxProviderInfo.Storage.CopyFileSystemEntry(MakePath(folderId), MakePath(toFolderId))) + throw new Exception("Error while copying"); + return ToFolder(GetFolderById(toFolderId).OfType().FirstOrDefault(x => x.Name == folder.Name)); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, string to) + { + return new Dictionary(); + } + + public string RenameFolder(Folder folder, string newTitle) + { + var entry = GetFolderById(folder.ID); + + var oldId = MakeId(entry); + var newId = oldId; + + if ("/".Equals(MakePath(folder.ID))) + { + //It's root folder + SharpBoxDaoSelector.RenameProvider(SharpBoxProviderInfo, newTitle); + //rename provider customer title + } + else + { + var parentFolder = GetFolderById(folder.ParentFolderID); + newTitle = GetAvailableTitle(newTitle, parentFolder, IsExist); + + //rename folder + if (SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) + { + //Folder data must be already updated by provider + //We can't search google folders by title because root can have multiple folders with the same name + //var newFolder = SharpBoxProviderInfo.Storage.GetFileSystemObject(newTitle, folder.Parent); + newId = MakeId(entry); + } + } + + UpdatePathInDB(oldId, newId); + + return newId; + } + + public int GetItemsCount(string folderId) + { + throw new NotImplementedException(); + } + + public bool IsEmpty(string folderId) + { + return GetFolderById(folderId).Count == 0; + } + + public bool UseTrashForRemove(Folder folder) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, string toRootFolderId) + { + return false; + } + + public bool CanCalculateSubitems(string entryId) + { + return false; + } + + public long GetMaxUploadSize(string folderId, bool chunkedUpload) + { + var storageMaxUploadSize = + chunkedUpload + ? SharpBoxProviderInfo.Storage.CurrentConfiguration.Limits.MaxChunkedUploadFileSize + : SharpBoxProviderInfo.Storage.CurrentConfiguration.Limits.MaxUploadFileSize; + + if (storageMaxUploadSize == -1) + storageMaxUploadSize = long.MaxValue; + + return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); + } + + #region Only for TMFolderDao + + public void ReassignFolders(string[] folderIds, Guid newOwnerId) + { + } + + public IEnumerable> Search(string text, bool bunch) + { + return null; + } + + public string GetFolderID(string module, string bunch, string data, bool createIfNotExists) + { + return null; + } + + public IEnumerable GetFolderIDs(string module, string bunch, IEnumerable data, bool createIfNotExists) + { + return new List(); + } + + public string GetFolderIDCommon(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDUser(bool createIfNotExists, Guid? userId) + { + return null; + } + + public string GetFolderIDShare(bool createIfNotExists) + { + return null; + } + + public string GetFolderIDTrash(bool createIfNotExists, Guid? userId) + { + return null; + } + + + public string GetFolderIDPhotos(bool createIfNotExists) + { + return null; + } + public string GetFolderIDProjects(bool createIfNotExists) + { + return null; + } + + public string GetBunchObjectID(string folderID) + { + return null; + } + + public Dictionary GetBunchObjectIDs(List folderIDs) + { + return null; + } + + #endregion + } + + public static class SharpBoxFolderDaoExtention + { + public static DIHelper AddSharpBoxFolderDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs new file mode 100644 index 0000000000..96cad0d038 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -0,0 +1,204 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; + +using AppLimit.CloudComputing.SharpBox; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Files.Core; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxProviderInfo : IProviderInfo, IDisposable + { + public int ID { get; set; } + public Guid Owner { get; set; } + public ILog Log { get; private set; } + + private nSupportedCloudConfigurations _providerKey; + public AuthData AuthData { get; set; } + + public SharpBoxProviderInfo(SharpBoxStorageDisposableWrapper storageDisposableWrapper, IOptionsMonitor monitor) + { + Wrapper = storageDisposableWrapper; + Log = monitor.CurrentValue; + } + //public SharpBoxProviderInfo(int id, string providerKey, string customerTitle, AuthData authData, Guid owner, FolderType rootFolderType, DateTime createOn) + //{ + // if (string.IsNullOrEmpty(providerKey)) + // throw new ArgumentNullException("providerKey"); + // if (string.IsNullOrEmpty(authData.Token) && string.IsNullOrEmpty(authData.Password)) + // throw new ArgumentNullException("token", "Both token and password can't be null"); + // if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password) && string.IsNullOrEmpty(authData.Token)) + // throw new ArgumentNullException("password", "Password can't be null"); + + // ID = id; + // CustomerTitle = customerTitle; + // Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; + + // _providerKey = (nSupportedCloudConfigurations)Enum.Parse(typeof(nSupportedCloudConfigurations), providerKey, true); + // _authData = authData; + // RootFolderType = rootFolderType; + // CreateOn = createOn; + //} + + public void Dispose() + { + if (StorageOpened) + { + Storage.Close(); + } + } + + internal CloudStorage Storage + { + get + { + if (Wrapper.Storage == null || !Wrapper.Storage.IsOpened) + { + return Wrapper.CreateStorage(AuthData, _providerKey); + } + return Wrapper.Storage; + } + } + + internal bool StorageOpened + { + get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; + } + + internal void UpdateTitle(string newtitle) + { + CustomerTitle = newtitle; + } + + public string CustomerTitle { get; set; } + + public DateTime CreateOn { get; set; } + + public string RootFolderId + { + get { return "sbox-" + ID; } + } + + public bool CheckAccess() + { + try + { + return Storage.GetRoot() != null; + } + catch (UnauthorizedAccessException) + { + return false; + } + catch (SharpBoxException ex) + { + Log.Error("Sharpbox CheckAccess error", ex); + return false; + } + } + + public void InvalidateStorage() + { + if (Wrapper != null) + { + Wrapper.Dispose(); + } + } + + public string ProviderKey + { + get { return _providerKey.ToString(); } + set { _providerKey = (nSupportedCloudConfigurations)Enum.Parse(typeof(nSupportedCloudConfigurations), value, true); } + } + + public FolderType RootFolderType { get; set; } + public SharpBoxStorageDisposableWrapper Wrapper { get; } + } + + class SharpBoxStorageDisposableWrapper : IDisposable + { + public CloudStorage Storage { get; private set; } + + + public SharpBoxStorageDisposableWrapper() + { + } + + internal CloudStorage CreateStorage(AuthData _authData, nSupportedCloudConfigurations _providerKey) + { + var prms = new object[] { }; + if (!string.IsNullOrEmpty(_authData.Url)) + { + var uri = _authData.Url; + if (Uri.IsWellFormedUriString(uri, UriKind.Relative)) + { + uri = Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri; + } + prms = new object[] { new Uri(uri) }; + } + + var storage = new CloudStorage(); + var config = CloudStorage.GetCloudConfigurationEasy(_providerKey, prms); + if (!string.IsNullOrEmpty(_authData.Token)) + { + if (_providerKey != nSupportedCloudConfigurations.BoxNet) + { + var token = storage.DeserializeSecurityTokenFromBase64(_authData.Token); + storage.Open(config, token); + } + } + else + { + storage.Open(config, new GenericNetworkCredentials { Password = _authData.Password, UserName = _authData.Login }); + } + return storage; + } + + public void Dispose() + { + if (Storage.IsOpened) + Storage.Close(); + } + } + + public static class SharpBoxProviderInfoExtension + { + public static DIHelper AddSharpBoxProviderInfoService(this DIHelper services) + { + services.TryAddScoped(); + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs new file mode 100644 index 0000000000..3f75077106 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs @@ -0,0 +1,102 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; +using ASC.Web.Studio.Core; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxSecurityDao : SharpBoxDaoBase, ISecurityDao + { + public SharpBoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + { + } + + public void SetShare(FileShareRecord r) + { + } + + public IEnumerable GetShares(IEnumerable subjects) + { + return null; + } + + public IEnumerable GetShares(IEnumerable> entry) + { + return null; + } + + public IEnumerable GetShares(FileEntry entry) + { + return null; + } + + public void RemoveSubject(Guid subject) + { + } + + public IEnumerable GetPureShareRecords(IEnumerable> entries) + { + return null; + } + + public IEnumerable GetPureShareRecords(FileEntry entry) + { + return null; + } + + public void DeleteShareRecords(IEnumerable records) + { + } + + public bool IsShared(object entryId, FileEntryType type) + { + throw new NotImplementedException(); + } + } + + public static class SharpBoxSecurityDaoExtention + { + public static DIHelper AddSharpBoxSecurityDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs new file mode 100644 index 0000000000..4b4b1fb365 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs @@ -0,0 +1,181 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; +using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Studio.Core; + +using Microsoft.Extensions.Options; + +namespace ASC.Files.Thirdparty.Sharpbox +{ + internal class SharpBoxTagDao : SharpBoxDaoBase, ITagDao + { + public SharpBoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + { + } + + #region ITagDao Members + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return null; + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + var folderId = SharpBoxDaoSelector.ConvertId(parentFolder.ID); + + var fakeFolderId = parentFolder.ID.ToString(); + + var entryIDs = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.Id.StartsWith(fakeFolderId)) + .Select(r => r.HashId) + .ToList(); + + if (!entryIDs.Any()) return new List(); + + var q = FilesDbContext.Tag + .Join(FilesDbContext.TagLink.DefaultIfEmpty(), + r => new TagLink { TenantId = r.TenantId, Id = r.Id }, + r => new TagLink { TenantId = r.TenantId, Id = r.TagId }, + (tag, tagLink) => new { tag, tagLink }, + new TagLinkComparer()) + .Where(r => r.tag.TenantId == TenantID) + .Where(r => r.tag.Flag == TagType.New) + .Where(r => r.tagLink.TenantId == TenantID) + .Where(r => entryIDs.Any(a => a == r.tagLink.EntryId)); + + if (subject != Guid.Empty) + { + q = q.Where(r => r.tag.Owner == subject); + } + + var tags = q + .ToList() + .Select(r => new Tag + { + TagName = r.tag.Name, + TagType = r.tag.Flag, + Owner = r.tag.Owner, + EntryId = MappingID(r.tagLink.EntryId), + EntryType = r.tagLink.EntryType, + Count = r.tagLink.TagCount, + Id = r.tag.Id + }); + + if (deepSearch) return tags; + + var folderFileIds = new[] { fakeFolderId } + .Concat(GetFolderSubfolders(folderId).Select(x => MakeId(x))) + .Concat(GetFolderFiles(folderId).Select(x => MakeId(x))); + + return tags.Where(tag => folderFileIds.Contains(tag.EntryId.ToString())); + } + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return null; + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return null; + } + + public IEnumerable SaveTags(IEnumerable tag) + { + return null; + } + + public IEnumerable SaveTags(Tag tag) + { + return null; + } + + public void UpdateNewTags(IEnumerable tag) + { + } + + public void UpdateNewTags(Tag tag) + { + } + + public void RemoveTags(IEnumerable tag) + { + } + + public void RemoveTags(Tag tag) + { + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return null; + } + + public void MarkAsNew(Guid subject, FileEntry fileEntry) + { + } + + #endregion + } + + public static class SharpBoxTagDaoExtention + { + public static DIHelper AddSharpBoxTagDaoService(this DIHelper services) + { + services.TryAddScoped(); + + return services; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/AppLimit.CloudComputing.SharpBox.csproj b/thirdparty/AppLimit.CloudComputing.SharpBox/AppLimit.CloudComputing.SharpBox.csproj new file mode 100644 index 0000000000..1c0761df4f --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/AppLimit.CloudComputing.SharpBox.csproj @@ -0,0 +1,27 @@ + + + 9.0.30729 + netstandard2.1 + + + AppLimit.CloudComputing.SharpBox + Ascensio System SIA + AppLimit.CloudComputing.SharpBox + (c) Ascensio System SIA. All rights reserved + false + + + + full + + + none + + + + + + + + + \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorage.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorage.cs new file mode 100644 index 0000000000..99a0cd0c42 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorage.cs @@ -0,0 +1,627 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Runtime.Serialization; +using System.Security.Cryptography.X509Certificates; + +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet; +using AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS; +using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox; +using AppLimit.CloudComputing.SharpBox.StorageProvider.FTP; +using AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs; +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav; + + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// The class CloudStorage implements all needed methods to get access + /// to a supported cloud storage infrastructure. The following vendors + /// are currently supported: + /// + /// - DropBox + /// + /// + public partial class CloudStorage : ICloudStoragePublicAPI + { + // some information for token storage + internal const string TokenProviderConfigurationType = "TokenProvConfigType"; + internal const string TokenCredentialType = "TokenCredType"; + internal const string TokenMetadataPrefix = "TokenMetadata"; + + #region Member Declarations + + private ICloudStorageProviderInternal _provider; + private ICloudStorageConfiguration _configuration; + private readonly Dictionary _configurationProviderMap; + + #endregion + + #region Constructure and logistics + + /// + /// returns the currently setted access token + /// + public ICloudStorageAccessToken CurrentAccessToken + { + get + { + if (_provider == null) + return null; + return _provider.CurrentAccessToken; + } + } + + /// + /// Allows access to the current configuration which was used in the open call + /// + public ICloudStorageConfiguration CurrentConfiguration + { + get { return _configuration; } + } + + /// + /// The default constructure for a cloudstorage + /// + public CloudStorage() + { + // build config provider + _configurationProviderMap = new Dictionary(); + + // register provider + RegisterStorageProvider(typeof(DropBoxConfiguration), typeof(DropBoxStorageProvider)); + RegisterStorageProvider(typeof(WebDavConfiguration), typeof(WebDavStorageProvider)); + RegisterStorageProvider(typeof(BoxNetConfiguration), typeof(BoxNetStorageProvider)); + RegisterStorageProvider(typeof(FtpConfiguration), typeof(FtpStorageProvider)); + RegisterStorageProvider(typeof(CIFSConfiguration), typeof(CIFSStorageProvider)); + RegisterStorageProvider(typeof(GoogleDocsConfiguration), typeof(GoogleDocsStorageProvider)); + RegisterStorageProvider(typeof(StorageProvider.SkyDrive.SkyDriveConfiguration), typeof(StorageProvider.SkyDrive.Logic.SkyDriveStorageProvider)); + } + + /// + /// copy ctor + /// + /// + public CloudStorage(CloudStorage src) + : this(src, true) + { + } + + /// + /// copy ctor + /// + /// + /// + public CloudStorage(CloudStorage src, bool openIfSourceWasOpen) + : this() + { + // copy all registered provider from src + _configurationProviderMap = src._configurationProviderMap; + + // open the provider + if (src.IsOpened && openIfSourceWasOpen) + Open(src._configuration, src.CurrentAccessToken); + else + _configuration = src._configuration; + } + + /// + /// This method allows to register a storage provider for a specific configuration + /// type + /// + /// + /// A + /// + /// + /// A + /// + /// + /// A + /// + public bool RegisterStorageProvider(Type configurationType, Type storageProviderType) + { + // do double check + if (_configurationProviderMap.ContainsKey(configurationType.FullName)) + return false; + + // register + _configurationProviderMap.Add(configurationType.FullName, storageProviderType); + + // go ahead + return true; + } + + /// + /// Ignores all invalid ssl certs + /// + /// + /// + /// + /// + /// + private static bool ValidateAllServerCertificates(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + } + + #endregion + + #region Base Functions + + /// + /// True when a the connection to the Cloudstorage will be established + /// + public bool IsOpened { get; private set; } + + /// + /// Calling this method with vendor specific configuration settings and token based credentials + /// to get access to the cloud storage. The following exceptions are possible: + /// + /// - System.UnauthorizedAccessException when the user provides wrong credentials + /// - AppLimit.CloudComputing.SharpBox.Exceptions.SharpBoxException when something + /// happens during cloud communication + /// + /// + /// Vendor specific configuration of the cloud storage + /// Vendor specific authorization token + /// A valid access token or null + public ICloudStorageAccessToken Open(ICloudStorageConfiguration configuration, ICloudStorageAccessToken token) + { + // check state + if (IsOpened) + return null; + + // ensures that the right provider will be used + SetProviderByConfiguration(configuration); + + // save the configuration + _configuration = configuration; + + // verify the ssl config + if (configuration.TrustUnsecureSSLConnections) + System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidateAllServerCertificates; + + // update the max connection settings + ServicePointManager.DefaultConnectionLimit = 250; + + // disable the not well implementes Expected100 header settings + ServicePointManager.Expect100Continue = false; + + // open the cloud connection + token = _provider.Open(configuration, token); + + // ok without Exception every is good + IsOpened = true; + + // return the token + return token; + } + + /// + /// This method will close the connection to the cloud storage system + /// + public void Close() + { + if (_provider == null) + return; + + _provider.Close(); + + IsOpened = false; + } + + /// + /// This method returns access to the root folder of the storage system + /// + /// Reference to the root folder of the storage system + public ICloudDirectoryEntry GetRoot() + { + return _provider == null ? null : _provider.GetRoot(); + } + + /// + /// This method returns access ro a specific subfolder or file addressed via + /// unix like file system path, e.g. /Public/SubFolder/SubSub + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// The path to the target subfolder + /// The startfolder for the searchpath + /// + public ICloudFileSystemEntry GetFileSystemObject(string name, ICloudDirectoryEntry parent) + { + return _provider == null ? null : _provider.GetFileSystemObject(name, parent); + } + + /// + /// This method creates a child folder in the give folder + /// of the cloud storage + /// + /// Name of the new folder + /// Parent folder + /// Reference to the created folder + public ICloudDirectoryEntry CreateFolder(string name, ICloudDirectoryEntry parent) + { + return _provider == null ? null : _provider.CreateFolder(name, parent); + } + + /// + /// This method removes a file or a directory from + /// the cloud storage + /// + /// Reference to the filesystem object which has to be removed + /// Returns true or false + public bool DeleteFileSystemEntry(ICloudFileSystemEntry fsentry) + { + return _provider != null && _provider.DeleteFileSystemEntry(fsentry); + } + + /// + /// This method moves a file or a directory from its current + /// location to a new onw + /// + /// Filesystem object which has to be moved + /// The new location of the targeted filesystem object + /// + public bool MoveFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + return _provider == null ? false : _provider.MoveFileSystemEntry(fsentry, newParent); + } + + /// + /// This method copy a file or a directory from its current + /// location to a new onw + /// + /// + /// + /// + public bool CopyFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + return _provider == null ? false : _provider.CopyFileSystemEntry(fsentry, newParent); + } + + /// + /// This mehtod allows to perform a server side renam operation which is basicly the same + /// then a move operation in the same directory + /// + /// + /// + /// + public bool RenameFileSystemEntry(ICloudFileSystemEntry fsentry, string newName) + { + return _provider == null ? false : _provider.RenameFileSystemEntry(fsentry, newName); + } + + /// + /// This method creates a new file object in the cloud storage. Use the GetContentStream method to + /// get a .net stream which usable in the same way then local stream are usable. + /// + /// Link to the parent container, null means the root directory + /// The name of the targeted file + /// + public ICloudFileSystemEntry CreateFile(ICloudDirectoryEntry parent, string name) + { + // pass through the provider + return _provider == null ? null : _provider.CreateFile(parent, name); + } + + /// + /// This method returns the direct URL to a specific file system object, + /// e.g. a file or folder + /// + /// A relative path to the file + /// A reference to the parent of the path + /// + public Uri GetFileSystemObjectUrl(string path, ICloudDirectoryEntry parent) + { + // pass through the provider + return _provider == null ? null : _provider.GetFileSystemObjectUrl(path, parent); + } + + /// + /// Returns the path of the targeted object + /// + /// + /// + public string GetFileSystemObjectPath(ICloudFileSystemEntry fsObject) + { + // pass through the provider + return _provider == null ? null : _provider.GetFileSystemObjectPath(fsObject); + } + + #endregion + + #region AccessTokenHandling + + /// + /// This method allows to store a security token into a serialization stream + /// + /// + /// + public Stream SerializeSecurityToken(ICloudStorageAccessToken token) + { + return SerializeSecurityToken(token, null); + } + + /// + /// This method allows to store a security token into a serialization stream and + /// makes it possible to store a couple of meta data as well + /// + /// + /// + /// + public Stream SerializeSecurityToken(ICloudStorageAccessToken token, Dictionary additionalMetaData) + { + if (!IsOpened) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorOpenedConnectionNeeded); + + return SerializeSecurityTokenEx(token, _configuration.GetType(), additionalMetaData); + } + + /// + /// This method can be used for serialize a token without have the connection opened :-) + /// + /// + /// + /// + /// + public Stream SerializeSecurityTokenEx(ICloudStorageAccessToken token, Type configurationType, Dictionary additionalMetaData) + { + var items = new Dictionary(); + var stream = new MemoryStream(); + var serializer = new DataContractSerializer(items.GetType()); + + // add the metadata + if (additionalMetaData != null) + { + foreach (KeyValuePair kvp in additionalMetaData) + { + items.Add(TokenMetadataPrefix + kvp.Key, kvp.Value); + } + } + + // save the token into our list + StoreToken(items, token, configurationType); + + // write the data to stream + serializer.WriteObject(stream, items); + + // go to start + stream.Seek(0, SeekOrigin.Begin); + + // go ahead + return stream; + } + + /// + /// This method stores a token into a file + /// + /// + /// + /// + /// + public void SerializeSecurityTokenEx(ICloudStorageAccessToken token, Type configurationType, Dictionary additionalMetaData, string fileName) + { + using (var fs = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + using (var ts = SerializeSecurityTokenEx(token, configurationType, additionalMetaData)) + { + // copy + StreamHelper.CopyStreamData(this, ts, fs, null, null); + } + + // flush + fs.Flush(); + + // close + fs.Close(); + } + } + + /// + /// This method allows to serialize a security token into a base64 string + /// + /// + /// + /// + /// + public string SerializeSecurityTokenToBase64Ex(ICloudStorageAccessToken token, Type configurationType, Dictionary additionalMetaData) + { + using (var tokenStream = SerializeSecurityTokenEx(token, configurationType, additionalMetaData)) + { + using (var memStream = new MemoryStream()) + { + // copy to memory + StreamHelper.CopyStreamData(this, tokenStream, memStream, null, null); + + // reset + memStream.Position = 0; + + // convert + return Convert.ToBase64String(memStream.ToArray()); + } + } + } + + /// + /// This method allows to load a token from a previously generated stream + /// + /// + /// + public ICloudStorageAccessToken DeserializeSecurityToken(Stream tokenStream) + { + Dictionary metadata; + return DeserializeSecurityToken(tokenStream, out metadata); + } + + /// + /// This method restores a tokene from file + /// + /// + /// + public ICloudStorageAccessToken DeserializeSecurityTokenEx(string fileName) + { + using (var fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None)) + { + return DeserializeSecurityToken(fs); + } + } + + /// + /// This method allows to load a token from a previously generated stream + /// and the attached metadata + /// + /// + /// + /// + public ICloudStorageAccessToken DeserializeSecurityToken(Stream tokenStream, out Dictionary additionalMetaData) + { + // load the data in our list + var serializer = new DataContractSerializer(typeof(Dictionary)); + + // check the type + var obj = serializer.ReadObject(tokenStream); + if (!obj.GetType().Equals(typeof(Dictionary))) + throw new InvalidDataException("A List was expected"); + + // evaluate the right provider + var tokendata = (Dictionary)obj; + + // find the right provider by typename + var provider = GetProviderByConfigurationTypeName(tokendata[TokenProviderConfigurationType]); + + // set the output parameter + additionalMetaData = new Dictionary(); + + // fill the metadata + foreach (var kvp in tokendata) + { + if (kvp.Key.StartsWith(TokenMetadataPrefix)) + { + additionalMetaData.Add(kvp.Key.Remove(0, TokenMetadataPrefix.Length), kvp.Value); + } + } + + // build the token + return provider.LoadToken(tokendata); + } + + /// + /// This methd allows to deserialize a base64 tokenstring + /// + /// + /// + public ICloudStorageAccessToken DeserializeSecurityTokenFromBase64(string tokenString) + { + Dictionary additionalMetaData; + return DeserializeSecurityTokenFromBase64(tokenString, out additionalMetaData); + } + + /// + /// This methd allows to deserialize a base64 tokenstring + /// + /// + /// + /// + public ICloudStorageAccessToken DeserializeSecurityTokenFromBase64(string tokenString, out Dictionary additionalMetaData) + { + // convert base64 to byte array + var data = Convert.FromBase64String(tokenString); + + // create a token stream + using (var tokenStream = new MemoryStream(data)) + { + // read the token stream + return DeserializeSecurityToken(tokenStream, out additionalMetaData); + } + } + + /// + /// This method stores the content of an access token in to + /// a list of string. This list can be serialized. + /// + /// Target list + /// the token + /// type of configguration which is responsable for the token + internal void StoreToken(Dictionary tokendata, ICloudStorageAccessToken token, Type configurationType) + { + // add the configuration information into the + tokendata.Add(TokenProviderConfigurationType, configurationType.FullName); + tokendata.Add(TokenCredentialType, token.GetType().FullName); + + // get the provider by toke + var provider = GetProviderByConfigurationTypeName(configurationType.FullName); + + // store all the other information to tokendata + provider.StoreToken(tokendata, token); + } + + /// + /// This method generated a access token from the given data + /// string list + /// + /// the string list + /// The unserialized token + internal ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + return _provider.LoadToken(tokendata); + } + + #endregion + + #region Helper + + private static ICloudStorageProviderInternal CreateProviderByType(Type providerType) + { + ICloudStorageProviderInternal provider; + + try + { + provider = Activator.CreateInstance(providerType) as ICloudStorageProviderInternal; + } + catch (Exception e) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCreateProviderInstanceFailed, e); + } + + if (provider == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCreateProviderInstanceFailed); + + return provider; + } + + private void SetProviderByConfiguration(ICloudStorageConfiguration configuration) + { + // check + if (configuration == null && _provider == null) + throw new InvalidOperationException("It's only allowed to set the configuration parameter to null when a provider was set before"); + + // read out the right provider type + SetProviderByConfigurationTypeName(configuration.GetType().FullName); + } + + private void SetProviderByConfigurationTypeName(string typeName) + { + _provider = GetProviderByConfigurationTypeName(typeName); + } + + private ICloudStorageProviderInternal GetProviderByConfigurationTypeName(string typeName) + { + // read out the right provider type + Type providerType; + if (!_configurationProviderMap.TryGetValue(typeName, out providerType)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorNoValidProviderFound); + + // build up the provider + return CreateProviderByType(providerType); + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageAsyncFunctions.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageAsyncFunctions.cs new file mode 100644 index 0000000000..b6cdc74362 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageAsyncFunctions.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using AppLimit.CloudComputing.SharpBox.Common; + +namespace AppLimit.CloudComputing.SharpBox +{ + public partial class CloudStorage + { + #region Async Functions + + internal class BackgroundRequest : AsyncObjectRequest + { + public object OperationResult; + public object OperationParameter; + } + + internal class OpenRequest : BackgroundRequest + { + public ICloudStorageConfiguration config; + public ICloudStorageAccessToken token; + } + + /// + /// This method implements a asyncallback for the open + /// request, which is describe in BeginOpenRequest + /// + /// A reference to the start object + private void OpenRequestCallback(object state) + { + // cast the request + var req = state as OpenRequest; + + try + { + // perform the request + req.OperationResult = Open(req.config, req.token); + } + catch (Exception e) + { + // failure to login + var openRequest = req.result.AsyncState as BackgroundRequest; + openRequest.OperationResult = null; + openRequest.errorReason = e; + } + + // call the async callback + req.callback(req.result); + } + + /// + /// Starts the async open request + /// + /// + /// + /// + /// + public IAsyncResult BeginOpenRequest(AsyncCallback callback, ICloudStorageConfiguration configuration, ICloudStorageAccessToken token) + { + // build the request data structure + var request = new OpenRequest { callback = callback }; + request.result = new AsyncResultEx(request); + request.config = configuration; + request.token = token; + + // add to threadpool + ThreadPool.QueueUserWorkItem(OpenRequestCallback, request); + + // return the result + return request.result; + } + + /// + /// Finishs the async open request + /// + /// + /// + public ICloudStorageAccessToken EndOpenRequest(IAsyncResult asyncResult) + { + var req = asyncResult.AsyncState as OpenRequest; + return req.OperationResult as ICloudStorageAccessToken; + } + + + /// + /// This method implements a asyncallback for the get childs + /// request, which is describe in BeginGetChildsRequest + /// + /// + private static void GetChildsRequestCallback(object state) + { + // cast the request + var req = state as BackgroundRequest; + + try + { + var retList = new List(); + + foreach (var e in req.OperationParameter as ICloudDirectoryEntry) + { + retList.Add(e); + } + + req.OperationResult = retList; + } + catch (Exception e) + { + // failure to login + var openRequest = req.result.AsyncState as BackgroundRequest; + openRequest.OperationResult = null; + openRequest.errorReason = e; + } + + // call the async callback + req.callback(req.result); + } + + /// + /// Starts the asyn get childs call + /// + /// + /// + /// + public IAsyncResult BeginGetChildsRequest(AsyncCallback callback, ICloudDirectoryEntry parent) + { + // build the request data structure + var request = new BackgroundRequest(); + request.callback = callback; + request.result = new AsyncResultEx(request); + request.OperationParameter = parent; + + // add to threadpool + ThreadPool.QueueUserWorkItem(GetChildsRequestCallback, request); + + // return the result + return request.result; + } + + /// + /// Finishes the async get childs call + /// + /// + /// + public List EndGetChildsRequest(IAsyncResult asyncResult) + { + var req = asyncResult.AsyncState as BackgroundRequest; + return req.OperationResult as List; + } + + + /// + /// This method implements a asyncallback for the getroot + /// request, which is describe in BeginGetRootRequest + /// + /// + private void GetRootRequestCallback(object state) + { + // cast the request + var req = state as BackgroundRequest; + + try + { + req.OperationResult = GetRoot(); + } + catch (Exception e) + { + // failure to login + var openRequest = req.result.AsyncState as BackgroundRequest; + openRequest.OperationResult = null; + openRequest.errorReason = e; + } + + // call the async callback + req.callback(req.result); + } + + /// + /// Starts the asyn getRoot call + /// + /// + /// + public IAsyncResult BeginGetRootRequest(AsyncCallback callback) + { + // build the request data structure + var request = new BackgroundRequest { callback = callback }; + request.result = new AsyncResultEx(request); + request.OperationParameter = null; + + // add to threadpool + ThreadPool.QueueUserWorkItem(GetRootRequestCallback, request); + + // return the result + return request.result; + } + + /// + /// Finishes the async getRoot call + /// + /// + /// + public ICloudDirectoryEntry EndGetRootRequest(IAsyncResult asyncResult) + { + var req = asyncResult.AsyncState as BackgroundRequest; + return req.OperationResult as ICloudDirectoryEntry; + } + + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageComfortFunctions.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageComfortFunctions.cs new file mode 100644 index 0000000000..d8e89bfe14 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageComfortFunctions.cs @@ -0,0 +1,807 @@ +using System; +using System.IO; +using System.Net; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +namespace AppLimit.CloudComputing.SharpBox +{ + public partial class CloudStorage + { + #region Comfort Functions + + /// + /// This method returns access ro a specific subfolder addressed via + /// unix like file system path, e.g. /Public/SubFolder/SubSub + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// The path to the target subfolder + /// Reference to the searched folder + public ICloudDirectoryEntry GetFolder(string path) + { + var ph = new PathHelper(path); + if (!ph.IsPathRooted()) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + + return GetFolder(path, null); + } + + /// + /// This method returns access ro a specific subfolder addressed via + /// unix like file system path, e.g. SubFolder/SubSub + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// The path to the target subfolder + /// A reference to the parent when a relative path was given + /// Reference to the searched folder + public ICloudDirectoryEntry GetFolder(string path, ICloudDirectoryEntry parent) + { + var dir = GetFileSystemObject(path, parent) as ICloudDirectoryEntry; + if (dir == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + return dir; + } + + /// + /// This method returns a folder without thrown an exception in the case of an error + /// + /// + /// + /// + public ICloudDirectoryEntry GetFolder(string path, bool throwException) + { + try + { + return GetFolder(path); + } + catch (SharpBoxException) + { + if (throwException) + throw; + + return null; + } + } + + /// + /// This method ... + /// + /// + /// + /// + /// + public ICloudDirectoryEntry GetFolder(string path, ICloudDirectoryEntry startFolder, bool throwException) + { + try + { + return GetFolder(path, startFolder); + } + catch (SharpBoxException) + { + if (throwException) + throw; + + return null; + } + } + + /// + /// This method returns access to a specific file addressed via + /// unix like file system path, e.g. /Public/SubFolder/SubSub + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// The path to the target subfolder + /// The startfolder for the searchpath + /// + public ICloudFileSystemEntry GetFile(string path, ICloudDirectoryEntry startFolder) + { + var fsEntry = GetFileSystemObject(path, startFolder); + if (fsEntry is ICloudDirectoryEntry) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + + return fsEntry; + } + + /// + /// This functions allows to download a specific file + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// + /// + /// + /// + public void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath) + { + DownloadFile(parent, name, targetPath, null); + } + + /// + /// This functions allows to download a specific file + /// + /// Valid Exceptions are: + /// SharpBoxException(nSharpBoxErrorCodes.ErrorFileNotFound); + /// + /// + /// + /// + /// + /// + public void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath, FileOperationProgressChanged delProgress) + { + // check parameters + if (parent == null || name == null || targetPath == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // expand environment in target path + targetPath = Environment.ExpandEnvironmentVariables(targetPath); + + // get the file entry + var file = parent.GetChild(name, true); + using (var targetData = new FileStream(Path.Combine(targetPath, file.Name), FileMode.Create, FileAccess.Write, FileShare.None)) + { + file.GetDataTransferAccessor().Transfer(targetData, nTransferDirection.nDownload, delProgress, null); + } + } + + /// + /// This function allows to download a specific file + /// + /// + /// + /// + public void DownloadFile(string filePath, string targetPath) + { + DownloadFile(filePath, targetPath, null); + } + + /// + /// This function allows to download a specific file + /// + /// + /// + /// + /// + public void DownloadFile(string filePath, string targetPath, FileOperationProgressChanged delProgress) + { + // check parameter + if (filePath == null || targetPath == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // download file + DownloadFile(container, file, targetPath, delProgress); + } + + /// + /// This method returns a data stream which allows to downloads the + /// file data + /// + /// + /// + /// + /// + public void DownloadFile(string name, ICloudDirectoryEntry parent, Stream targetStream) + { + // check parameters + if (parent == null || name == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get the file entry + var file = parent.GetChild(name, true); + + // download the data + file.GetDataTransferAccessor().Transfer(targetStream, nTransferDirection.nDownload); + } + + /// + /// This function allowes to upload a local file + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer) + { + return UploadFile(filePath, targetContainer, (FileOperationProgressChanged)null); + } + + /// + /// This function allowes to upload a local file + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, FileOperationProgressChanged delProgress) + { + // check parameters + if (string.IsNullOrEmpty(filePath)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + return UploadFile(filePath, targetContainer, Path.GetFileName(filePath), delProgress); + } + + /// + /// This function allowes to upload a local file. Remote file will be created with the name specifed by + /// the targetFileName argument + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, string targetFileName) + { + return UploadFile(filePath, targetContainer, targetFileName, null); + } + + /// + /// This function allowes to upload a local file. Remote file will be created with the name specifed by + /// the targetFileName argument + /// + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, string targetFileName, FileOperationProgressChanged delProgress) + { + // check parameter + if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(targetFileName) || targetContainer == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // check if the target is a real file + if (!File.Exists(filePath)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + // build the source stream + using (var srcStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + // create the upload file + var newFile = CreateFile(targetContainer, targetFileName); + if (newFile == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + // upload the data + newFile.GetDataTransferAccessor().Transfer(srcStream, nTransferDirection.nUpload, delProgress, null); + + // go ahead + return newFile; + } + } + + /// + /// This function allows to upload a local file + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory) + { + return UploadFile(filePath, targetDirectory, (FileOperationProgressChanged)null); + } + + /// + /// This function allows to upload a local file + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, FileOperationProgressChanged delProgress) + { + // check parameters + if (string.IsNullOrEmpty(filePath)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + return UploadFile(filePath, targetDirectory, Path.GetFileName(filePath), delProgress); + } + + /// + /// This function allows to upload a local file. Remote file will be created with the name specifed by + /// the targetFileName argument + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, string targetFileName) + { + return UploadFile(filePath, targetDirectory, targetFileName, null); + } + + /// + /// This function allows to upload a local file. Remote file will be created with the name specifed by + /// the targetFileName argument + /// + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, string targetFileName, FileOperationProgressChanged delProgress) + { + // check parameters + if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(targetFileName) || targetDirectory == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get target container + var target = GetFolder(targetDirectory); + if (target == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + // upload file + using (Stream s = File.OpenRead(filePath)) + { + return UploadFile(s, targetFileName, target, delProgress); + } + } + + /// + /// This method allows to upload the data from a given filestream into a target file + /// + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(Stream uploadDataStream, string targetFileName, ICloudDirectoryEntry targetContainer, FileOperationProgressChanged delProgress) + { + // check parameters + if (string.IsNullOrEmpty(targetFileName) || uploadDataStream == null || targetContainer == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // create the upload file + var newFile = CreateFile(targetContainer, targetFileName); + if (newFile == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + // upload data + newFile.GetDataTransferAccessor().Transfer(uploadDataStream, nTransferDirection.nUpload, delProgress, null); + + // go ahead + return newFile; + } + + /// + /// This method allows to upload the data from a given filestream into a target file + /// + /// + /// + /// + /// + public ICloudFileSystemEntry UploadFile(Stream uploadDataStream, string targetFileName, ICloudDirectoryEntry targetContainer) + { + return UploadFile(uploadDataStream, targetFileName, targetContainer, null); + } + + /// + /// This function allows to create full folder pathes in the cloud storage + /// + /// + /// + public ICloudDirectoryEntry CreateFolder(string path) + { + // get the path elemtens + var ph = new PathHelper(path); + + // check parameter + if (!ph.IsPathRooted()) + return null; + + // start creation + return CreateFolderEx(path, GetRoot()); + } + + /// + /// This function allows to create full folder pathes in the cloud storage + /// + /// + /// + /// + public ICloudDirectoryEntry CreateFolderEx(string path, ICloudDirectoryEntry entry) + { + // get the path elemtens + var ph = new PathHelper(path); + + var pes = ph.GetPathElements(); + + // check which elements are existing + foreach (var el in pes) + { + // check if subfolder exists, if it doesn't, create it + var cur = GetFolder(el, entry, false); + + // create if needed + if (cur == null) + { + var newFolder = CreateFolder(el, entry); + if (newFolder == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCreateOperationFailed); + + cur = newFolder; + } + + // go ahead + entry = cur; + } + + // return + return entry; + } + + /// + /// This function allows to delete a specific file or directory + /// + /// File or directory path which has to be deleted + /// + public bool DeleteFileSystemEntry(string filePath) + { + // check parameter + if (filePath == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // get filesystem entry + var fsEntry = GetFileSystemObject(file, container); + if (fsEntry == null) return false; + + // delete file + return DeleteFileSystemEntry(fsEntry); + } + + /// + /// This method moves a file or a directory from its current + /// location to a new onw + /// + /// Filesystem object which has to be moved + /// /// The new location of the targeted filesystem object + /// + public bool MoveFileSystemEntry(string filePath, string newParentPath) + { + // check parameter + if ((filePath == null) || (newParentPath == null)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // get filesystem entry + var fsEntry = GetFileSystemObject(file, container); + + // get new parent path + var newParent = GetFolder(newParentPath); + + // move file + return MoveFileSystemEntry(fsEntry, newParent); + } + + /// + /// This method moves a file or a directory from its current + /// location to a new onw + /// + /// Filesystem object which has to be moved + /// /// The new location of the targeted filesystem object + /// + public bool CopyFileSystemEntry(string filePath, string newParentPath) + { + // check parameter + if ((filePath == null) || (newParentPath == null)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // get filesystem entry + var fsEntry = GetFileSystemObject(file, container); + + // get new parent path + var newParent = GetFolder(newParentPath); + + // move file + return CopyFileSystemEntry(fsEntry, newParent); + } + + /// + /// This mehtod allows to perform a server side renam operation which is basicly the same + /// then a move operation in the same directory + /// + /// File or directory which has to be renamed + /// The new name of the targeted filesystem object + /// + public bool RenameFileSystemEntry(string filePath, string newName) + { + // check parameter + if ((filePath == null) || (newName == null)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // get filesystem entry + var fsEntry = GetFileSystemObject(file, container); + + // rename file + return RenameFileSystemEntry(fsEntry, newName); + } + + /// + /// This method creates a new file object in the cloud storage. Use the GetContentStream method to + /// get a .net stream which usable in the same way then local stream are usable + /// + /// The name of the targeted file + /// + public ICloudFileSystemEntry CreateFile(string filePath) + { + // check parameter + if (filePath == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get path and filename + var ph = new PathHelper(filePath); + var dir = ph.GetDirectoryName(); + var file = ph.GetFileName(); + + // check if we are in root + if (dir.Length == 0) + dir = "/"; + + // get parent container + var container = GetFolder(dir); + + // rename file + return CreateFile(container, file); + } + + /// + /// This method serializes a token into an opened stream object + /// + /// + /// + public void SerializeSecurityTokenToStream(ICloudStorageAccessToken token, Stream targetStream) + { + // open the token stream + using (var tokenStream = SerializeSecurityToken(token)) + { + StreamHelper.CopyStreamData(this, tokenStream, targetStream, null, null); + } + } + + #endregion + + #region Configuration Mapping + + /// + /// This method maps a given type of supporte cloud storage provider into a working standard configuration. The parameters + /// field has to be filled out as follows: + /// DropBox - nothing + /// BoxNet - nothing + /// StoreGate - Use ICredentials for authentication (service will be calculated from this) + /// SmartDriv - nothing + /// WebDav - The URL of the webdav service + /// + /// + /// + /// + public static ICloudStorageConfiguration GetCloudConfigurationEasy(nSupportedCloudConfigurations configtype, params object[] param) + { + var cl = new CloudStorage(); + return cl.GetCloudConfiguration(configtype, param); + } + + /// + /// This method maps a given type of supporte cloud storage provider into a working standard configuration. The parameters + /// field has to be filled out as follows: + /// DropBox - nothing + /// BoxNet - nothing + /// StoreGate - Use ICredentials for authentication (service will be calculated from this) + /// SmartDriv - nothing + /// WebDav - The URL of the webdav service + /// + /// + /// + /// + public ICloudStorageConfiguration GetCloudConfiguration(nSupportedCloudConfigurations configtype, params object[] param) + { + switch (configtype) + { + case nSupportedCloudConfigurations.DropBox: + return StorageProvider.DropBox.DropBoxConfiguration.GetStandardConfiguration(); + case nSupportedCloudConfigurations.BoxNet: + return StorageProvider.BoxNet.BoxNetConfiguration.GetBoxNetConfiguration(); + case nSupportedCloudConfigurations.StoreGate: + { + // check parameters + if (param.Length < 1 || (param[0] as ICredentials) == null) + { + var e = new Exception("Missing valid credentials for StoreGate in the first parameter"); + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters, e); + } + + // cast creds + var creds = (ICredentials)param[0]; + + // build config + return StorageProvider.WebDav.WebDavConfiguration.GetStoreGateConfiguration(creds.GetCredential(null, "")); + } + case nSupportedCloudConfigurations.SmartDrive: + return StorageProvider.WebDav.WebDavConfiguration.Get1and1Configuration(); + case nSupportedCloudConfigurations.WebDav: + { + // check parameters + if (param.Length < 1 || (param[0] as Uri) == null) + { + var e = new Exception("Missing URL for webdav server in the first parameter"); + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters, e); + } + + // convert to uri + var uri = (Uri)param[0]; + + // create the config + var cfg = new StorageProvider.WebDav.WebDavConfiguration(uri) { TrustUnsecureSSLConnections = true }; + + // go ahead + return cfg; + } + case nSupportedCloudConfigurations.CloudMe: + { + // check parameters + if (param.Length < 1 || (param[0] as ICredentials) == null) + { + var e = new Exception("Missing valid credentials for CloudMe in the first parameter"); + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters, e); + } + + // cast creds + var creds = (ICredentials)param[0]; + + // build config + return StorageProvider.WebDav.WebDavConfiguration.GetCloudMeConfiguration(creds.GetCredential(null, "")); + } + case nSupportedCloudConfigurations.HiDrive: + return StorageProvider.WebDav.WebDavConfiguration.GetHiDriveConfiguration(); + case nSupportedCloudConfigurations.Google: + return StorageProvider.GoogleDocs.GoogleDocsConfiguration.GetStandartConfiguration(); + case nSupportedCloudConfigurations.Yandex: + return StorageProvider.WebDav.WebDavConfiguration.GetYandexConfiguration(); + case nSupportedCloudConfigurations.SkyDrive: + return new StorageProvider.SkyDrive.SkyDriveConfiguration(); + default: + { + var e = new Exception("Unknow service type"); + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters, e); + } + } + } + + #endregion + + #region Helpers + + /// + /// Just a helper for the stream copy process + /// + /// + /// + /// + /// + internal static StreamHelperResultCodes FileStreamCopyCallback(object sender, StreamHelperProgressEvent pe, params object[] data) + { + // check array + if (data.Length != 3) + return StreamHelperResultCodes.OK; + + // get the progess delegate + var pc = data[0] as FileOperationProgressChanged; + if (pc == null) + return StreamHelperResultCodes.OK; + + // get the file + var e = data[1] as ICloudFileSystemEntry; + if (e == null) + return StreamHelperResultCodes.OK; + + // get the progress context + var progressContext = data[2]; + + // create the eventargs element + var arg = new FileDataTransferEventArgs + { + FileSystemEntry = e, + CurrentBytes = pe.ReadBytesTotal, + CustomnContext = progressContext, + PercentageProgress = pe.PercentageProgress, + TransferRateTotal = pe.TransferRateTotal, + TransferRateCurrent = pe.TransferRateCurrent, + TotalBytes = pe.TotalLength == -1 ? e.Length : pe.TotalLength + }; + + // calc transfertime + if (pe.TransferRateTotal != -1 && pe.TransferRateTotal > 0) + { + var bytesPerSecond = (arg.TransferRateTotal/8)*1000; + + if (bytesPerSecond > 0) + { + var neededSeconds = (arg.TotalBytes - arg.CurrentBytes)/bytesPerSecond; + arg.OpenTransferTime = new TimeSpan(neededSeconds*TimeSpan.TicksPerSecond); + } + else + arg.OpenTransferTime = new TimeSpan(long.MaxValue); + } + else + arg.OpenTransferTime = new TimeSpan(long.MaxValue); + + // call it + pc(sender, arg); + + // create the ret value + if (arg.Cancel) + return StreamHelperResultCodes.Aborted; + + return StreamHelperResultCodes.OK; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageLimits.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageLimits.cs new file mode 100644 index 0000000000..57ad25cbd0 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageLimits.cs @@ -0,0 +1,43 @@ +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This class contains the limits of a given cloud storage + /// configuration + /// + public class CloudStorageLimits + { + /// + /// Default ctor which sets the limits to an + /// unlimited value (no limits) + /// + public CloudStorageLimits() + : this(-1, -1) + { + } + + /// + /// Special ctor which allows to initials the limits with + /// special values in an external protocol provider + /// + /// + /// + public CloudStorageLimits(long maxUploadFileSize, long maxDownloadFileSite) + { + MaxUploadFileSize = maxUploadFileSize; + MaxChunkedUploadFileSize = MaxUploadFileSize; + MaxDownloadFileSize = maxDownloadFileSite; + } + + /// + /// defines the maximum file size in bytes during upload + /// + public long MaxUploadFileSize { get; internal set; } + + public long MaxChunkedUploadFileSize { get; internal set; } + + /// + /// defines the maximum file size in bytes during download + /// + public long MaxDownloadFileSize { get; internal set; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageSyncFramework.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageSyncFramework.cs new file mode 100644 index 0000000000..9fee0ff5a5 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/CloudStorageSyncFramework.cs @@ -0,0 +1,250 @@ +using System; +using System.IO; +using System.Text; +using AppLimit.CloudComputing.SharpBox.SyncFramework; + +namespace AppLimit.CloudComputing.SharpBox +{ + public partial class CloudStorage + { + /// + /// This flags are used to control the folder + /// synchronization. + /// + [Flags] + public enum SyncFolderFlags + { + /// + /// Place holder for empty + /// + Empty = 0x00000000, + + /// + /// Just upload file from local to remote + /// + UploadItems = 0x00000001, + + /// + /// Just download files from remote to local + /// + DownloadItems = 0x00000002, + + /// + /// Remove files which are not available in remote + /// + RemoveMissingFiles = 0x00000004, + + /// + /// Performe the action recursively + /// + Recursive = 0x00000008, + + /// + /// Synchronize all, which combines the right flags + /// + Synchronize = UploadItems | DownloadItems | RemoveMissingFiles | Recursive + } + + /// + /// This function allows to synchronize a local folder with an folder exists in the cloud storage + /// and vice versa. The local folder and the target folder has to be created before. + /// + /// + /// + /// + /// + public bool SynchronizeFolder(DirectoryInfo srcFolder, ICloudDirectoryEntry tgtFolder, SyncFolderFlags flags) + { + // init ret value + var bRet = true; + + // init helper parameter + var bRecursive = ((flags & SyncFolderFlags.Recursive) != 0); + + // init the differ + var diff = new DirectoryDiff(srcFolder, tgtFolder); + + // build the diff results + var res = diff.Compare(bRecursive); + + // process the diff result + foreach (var item in res) + { + switch (item.compareResult) + { + case ComparisonResult.Identical: + { + continue; + } + case ComparisonResult.MissingInLocalFolder: + { + // check of the upload flag was set + if ((flags & SyncFolderFlags.DownloadItems) != SyncFolderFlags.DownloadItems) + continue; + + // copy remote to local or create path + + // 1. get the rel path + string relPath; + if (item.remoteItem is ICloudDirectoryEntry) + relPath = GetFullCloudPath(tgtFolder, item.remoteItem, '\\'); + else + relPath = GetFullCloudPath(tgtFolder, item.remoteItem.Parent, '\\'); + + // 2. ensure the directory exists + var tgtPath = Path.Combine(srcFolder.FullName, relPath); + if (!Directory.Exists(tgtPath)) + Directory.CreateDirectory(tgtPath); + + // 3. download file if needed + if (!(item.remoteItem is ICloudDirectoryEntry)) + { + DownloadFile(item.remoteItem.Parent, item.remoteItem.Name, tgtPath); + } + break; + } + case ComparisonResult.MissingInRemoteFolder: + { + // check of the upload flag was set + if ((flags & SyncFolderFlags.UploadItems) != SyncFolderFlags.UploadItems) + continue; + + // copy local to remote + + // 1. get the rel path + string relPath; + if ((item.localItem.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + relPath = item.localItem.FullName.Remove(0, srcFolder.FullName.Length); + else + relPath = Path.GetDirectoryName(item.localItem.FullName).Remove(0, srcFolder.FullName.Length); + + // 2. convert delimit + relPath = relPath.Replace(Path.DirectorySeparatorChar, '/'); + + // 3. ensure the directory exists + ICloudDirectoryEntry realTarget; + + if (relPath.Length == 0) + realTarget = tgtFolder; + else + { + if (relPath[0] == '/') + relPath = relPath.Remove(0, 1); + + //check if subfolder exists, if it doesn't, create it + realTarget = GetFolder(relPath, tgtFolder) ?? CreateFolderEx(relPath, tgtFolder); + } + + // 4. check target + if (realTarget == null) + { + bRet = false; + continue; + } + + // 5. upload file if needed + if ((item.localItem.Attributes & FileAttributes.Directory) != FileAttributes.Directory) + { + if (UploadFile(item.localItem.FullName, realTarget) == null) + bRet = false; + } + break; + } + + case ComparisonResult.SizeDifferent: + { + throw new NotImplementedException(); + } + } + } + + return bRet; + } + + /// + /// This function allows to synchronize a local folder with an folder exists in the cloud storage + /// and vice versa. The local folder and the target folder has to be created before. + /// + /// + /// + /// + /// + public bool SynchronizeFolder(string srcFolder, string tgtFolder, SyncFolderFlags flags) + { + // check parameters + if (srcFolder == null || tgtFolder == null || flags == SyncFolderFlags.Empty) + return false; + + // build directory info for local folder + var srcFolderInfo = new DirectoryInfo(srcFolder); + + // build the target folder + var tgtFolderEntry = GetFolder(tgtFolder); + if (tgtFolderEntry == null) + return false; + + // call the sync job + return SynchronizeFolder(srcFolderInfo, tgtFolderEntry, flags); + } + + /// + /// Returns a path to the file object + /// + /// + /// + public static string GetFullCloudPath(ICloudFileSystemEntry fsentry) + { + return GetFullCloudPath(fsentry, '/'); + } + + /// + /// Returns a path to the file object + /// + /// start entry + /// delimiter + /// + public static string GetFullCloudPath(ICloudFileSystemEntry fsentry, char cDelimiter) + { + // create string builder + var sb = new StringBuilder(); + + // add the object as self + sb.Insert(0, fsentry.Name); + + // add the delimiter + sb.Insert(0, cDelimiter); + + // visit every parent + var current = fsentry.Parent; + while (current != null) + { + // add the item + sb.Insert(0, current.Name); + + // add the delimiter + sb.Insert(0, cDelimiter); + + // go up + current = current.Parent; + } + + // return result + return sb.ToString(); + } + + /// + /// + /// + /// + /// + /// + /// + public static string GetFullCloudPath(ICloudDirectoryEntry start, ICloudFileSystemEntry fsentry, char cDelimiter) + { + var strfsentry = GetFullCloudPath(fsentry, cDelimiter); + var strStart = GetFullCloudPath(start, cDelimiter); + + return strfsentry.Remove(0, strStart.Length); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncObjectRequest.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncObjectRequest.cs new file mode 100644 index 0000000000..a511b6dc62 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncObjectRequest.cs @@ -0,0 +1,28 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.Common +{ + /// + /// This class implements an object request for all + /// async operations in SharpBox + /// + public class AsyncObjectRequest + { + /// + /// Reference to the callback which will be called + /// at the end of an async operation + /// + public AsyncCallback callback; + + /// + /// The generated asyncresult + /// + public IAsyncResult result; + + /// + /// In case of error the cached execption which can + /// be handled in the EndRequest method + /// + public Exception errorReason; + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncResultEx.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncResultEx.cs new file mode 100644 index 0000000000..671aa7b851 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/AsyncResultEx.cs @@ -0,0 +1,50 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.Common +{ + /// + /// This class implements the used async result class + /// which will be generated in all async operations + /// + public class AsyncResultEx : IAsyncResult + { + /// + /// ctor of AsyncResultEx which handles + /// the used state object + /// + /// + public AsyncResultEx(object asyncState) + { + AsyncState = asyncState; + } + + /// + /// This properties allows read access to the state object + /// + public object AsyncState { get; private set; } + + /// + /// The wait handle, which is not needed in SharpBox + /// + public System.Threading.WaitHandle AsyncWaitHandle + { + get { throw new NotImplementedException(); } + } + + /// + /// The sync boolean, which is not needed in SharpBox + /// + public bool CompletedSynchronously + { + get { throw new NotImplementedException(); } + } + + /// + /// IsCompleted, which is not needed in SharpBox + /// + public bool IsCompleted + { + get { throw new NotImplementedException(); } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionary.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionary.cs new file mode 100644 index 0000000000..a2dea8c131 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionary.cs @@ -0,0 +1,109 @@ +using System; +using System.Diagnostics; + +using Microsoft.Extensions.Caching.Memory; + +namespace AppLimit.CloudComputing.SharpBox.Common.Cache +{ + public sealed class CachedDictionary : CachedDictionaryBase + { + private readonly TimeSpan _absoluteExpirationPeriod; + + private DateTime AbsoluteExpiration + { + get + { + if (_absoluteExpirationPeriod == TimeSpan.Zero) + return DateTime.MaxValue; + return DateTime.Now + _absoluteExpirationPeriod; + } + } + + private TimeSpan SlidingExpiration { get; set; } + private MemoryCache MemoryCache { get; set; } + + public CachedDictionary(string baseKey, TimeSpan absoluteExpirationPeriod, TimeSpan slidingExpiration, Func cacheCodition) + { + MemoryCache = new MemoryCache(new MemoryCacheOptions()); + _baseKey = baseKey; + _absoluteExpirationPeriod = absoluteExpirationPeriod; + SlidingExpiration = slidingExpiration; + _cacheCodition = cacheCodition ?? throw new ArgumentNullException("cacheCodition"); + InsertRootKey(_baseKey); + } + + public CachedDictionary(string baseKey) + : this(baseKey, x => true) + { + } + + public CachedDictionary(string baseKey, Func cacheCodition) + : this(baseKey, TimeSpan.Zero, TimeSpan.Zero, cacheCodition) + { + } + + protected override void InsertRootKey(string rootKey) + { +#if (DEBUG) + Debug.Print("inserted root key {0}", rootKey); +#endif + MemoryCache.Remove(rootKey); + MemoryCache.Set(rootKey, DateTime.UtcNow.Ticks, new MemoryCacheEntryOptions() { AbsoluteExpiration = DateTime.MaxValue, SlidingExpiration = TimeSpan.Zero, Priority = CacheItemPriority.NeverRemove }); + } + + public override void Reset(string rootKey, string key) + { + MemoryCache.Remove(BuildKey(key, rootKey)); + } + + protected override object GetObjectFromCache(string fullKey) + { + return MemoryCache.Get(fullKey); + } + + public override void Add(string rootkey, string key, T newValue) + { + var builtrootkey = BuildKey(string.Empty, string.IsNullOrEmpty(rootkey) ? "root" : rootkey); + if (!MemoryCache.TryGetValue(builtrootkey, out _)) + { +#if (DEBUG) + Debug.Print("added root key {0}", builtrootkey); +#endif + //Insert root if no present + MemoryCache.Remove(builtrootkey); + MemoryCache.Set(builtrootkey, DateTime.UtcNow.Ticks, new MemoryCacheEntryOptions + { + AbsoluteExpiration = AbsoluteExpiration, + SlidingExpiration = SlidingExpiration + }); + + MemoryCache.Remove(BuildKey(key, rootkey)); + } + + if (newValue != null) + { + var buildKey = BuildKey(key, rootkey); + MemoryCache.Remove(buildKey); + var options = new MemoryCacheEntryOptions + { + Priority = CacheItemPriority.Normal, + AbsoluteExpiration = AbsoluteExpiration, + SlidingExpiration = SlidingExpiration, + }; + MemoryCache.Set(BuildKey(key, rootkey), newValue, new MemoryCacheEntryOptions + { + Priority = CacheItemPriority.Normal, + AbsoluteExpiration = AbsoluteExpiration, + SlidingExpiration = SlidingExpiration + }); + //TODO + //options.AddExpirationToken(Microsoft.Extensions.Primitives.CancellationChangeToken); + //new CacheDependency(null, new[] { _baseKey, builtrootkey }), + } + else + { + MemoryCache.Remove(BuildKey(key, rootkey)); //Remove if null + } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionaryBase.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionaryBase.cs new file mode 100644 index 0000000000..69ac522dc6 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Cache/CachedDictionaryBase.cs @@ -0,0 +1,132 @@ +using System; +using System.Diagnostics; +using System.Linq; + +namespace AppLimit.CloudComputing.SharpBox.Common.Cache +{ + public abstract class CachedDictionaryBase + { + protected string _baseKey; + protected Func _cacheCodition; + + protected long ClearId + { + get { return DateTime.UtcNow.Ticks; } + } + + public T this[string key] + { + get { return Get(key); } + } + + public T this[Func @default] + { + get { return Get(@default); } + } + + protected abstract void InsertRootKey(string rootKey); + + public void Clear() + { + InsertRootKey(_baseKey); + } + + public void Clear(string rootKey) + { + InsertRootKey(BuildKey(string.Empty, rootKey)); + } + + public void Reset(string key) + { + Reset(string.Empty, key); + } + + public abstract void Reset(string rootKey, string key); + + public T Get(string key) + { + return Get(string.Empty, key, null); + } + + public T Get(string key, Func defaults) + { + return Get(string.Empty, key, defaults); + } + + + public void Add(string key, T newValue) + { + Add(string.Empty, key, newValue); + } + + public abstract void Add(string rootkey, string key, T newValue); + + public bool HasItem(string key) + { + return !Equals(Get(key), default(T)); + } + + protected string BuildKey(string key, string rootkey) + { + return string.Format("{0}-{1}-{2}", _baseKey, rootkey, key); + } + + protected abstract object GetObjectFromCache(string fullKey); + + public T Get(Func @default) + { + string key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name, + @default.Method.DeclaringType.FullName, + string.Join(",", + @default.Method.GetGenericArguments().Select(x => x.FullName).ToArray + ())); + return Get(key, @default); + } + + protected virtual bool FitsCondition(object cached) + { + return cached != null && cached is T; + } + + public virtual T Get(string rootkey, string key, Func defaults) + { + var fullKey = BuildKey(key, rootkey); + var objectCache = GetObjectFromCache(fullKey); + if (FitsCondition(objectCache)) + { +#if (DEBUG) + OnHit(fullKey); +#endif + return ReturnCached(objectCache); + } + if (defaults != null) + { +#if (DEBUG) + OnMiss(fullKey); +#endif + var newValue = defaults(); + if (_cacheCodition == null || _cacheCodition(newValue)) + { + Add(rootkey, key, newValue); + } + return newValue; + } + return default(T); + } + + protected virtual T ReturnCached(object objectCache) + { + return (T)objectCache; + } + + protected virtual void OnHit(string fullKey) + { + Debug.Print("cache hit:{0}", fullKey); + } + + protected virtual void OnMiss(string fullKey) + { + Debug.Print("cache miss:{0}", fullKey); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Extensions/SharpBoxExtensions.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Extensions/SharpBoxExtensions.cs new file mode 100644 index 0000000000..a317090988 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Extensions/SharpBoxExtensions.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using System.Xml.Linq; + +namespace AppLimit.CloudComputing.SharpBox.Common.Extensions +{ + public static class SharpBoxExtensions + { + private const int BufferSize = 2048; + + public static void CopyTo(this Stream src, Stream dst) + { + if (src == null || dst == null) + return; + + var buffer = new byte[BufferSize]; + int readed; + while ((readed = src.Read(buffer, 0, BufferSize)) > 0) + { + dst.Write(buffer, 0, readed); + } + } + + public static string ReplaceFirst(this string src, string replace, string replaceWith) + { + var ind = src.IndexOf(replace, StringComparison.InvariantCulture); + + if (ind != -1) + { + src = src.Remove(ind, replace.Length).Insert(ind, replaceWith); + } + + return src; + } + + public static string ReplaceLast(this string src, string replace, string replaceWith) + { + var ind = src.LastIndexOf(replace, StringComparison.InvariantCulture); + + if (ind != -1) + { + src = src.Remove(ind, replace.Length).Insert(ind, replaceWith); + } + + return src; + } + + public static XAttribute AttributeOrNull(this XElement el, string attr) + { + return el != null ? el.Attribute(attr) : null; + } + + public static string ValueOrEmpty(this XElement el) + { + return el != null ? el.Value : string.Empty; + } + + public static string ValueOrEmpty(this XAttribute attr) + { + return attr != null ? attr.Value : string.Empty; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/PathHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/PathHelper.cs new file mode 100644 index 0000000000..b955aacbbd --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/PathHelper.cs @@ -0,0 +1,89 @@ +using System; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.Common.IO +{ + /// + /// A class with reimplements some aspects if the Path clas + /// to make the handling of path names easier + /// + public class PathHelper + { + private readonly string _path; + + /// + /// The used path delimiter + /// + public const char Delimiter = '/'; + + /// + /// ctor with access path + /// + /// + public PathHelper(string path) + { + _path = path; + } + + /// + /// Checks if the given path is rooted + /// + /// + public bool IsPathRooted() + { + return _path.Length != 0 && _path[0] == Delimiter; + } + + /// + /// Returns all path elements in a path + /// + /// + public string[] GetPathElements() + { + // remove heading and trailing / + var workingPath = IsPathRooted() ? _path.Remove(0, 1) : _path; + + workingPath = workingPath.TrimEnd(Delimiter); + + return workingPath.Length == 0 ? new string[0] : workingPath.Split(Delimiter); + } + + /// + /// Returns the directory name + /// + /// + public string GetDirectoryName() + { + var idx = _path.LastIndexOf(Delimiter); + return idx == 0 ? "" : _path.Substring(0, idx); + } + + /// + /// Returns the filename + /// + /// + public string GetFileName() + { + return Path.GetFileName(_path); + } + + /// + /// Combines several path elements + /// + /// + /// + /// + public static string Combine(string left, string right) + { + // remove delimiter + right = right.TrimStart(Delimiter); + left = left.TrimEnd(Delimiter); + + // build the path + if (right.Length == 0) + return left; + + return left + Delimiter + right; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/StreamHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/StreamHelper.cs new file mode 100644 index 0000000000..e4d0c1dbe8 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/IO/StreamHelper.cs @@ -0,0 +1,255 @@ +using System; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.Common.IO +{ + /// + /// Defines the action which will done from the streamhelper after calling the callback + /// + internal enum StreamHelperResultCodes + { + /// + /// go forward with stream transfer + /// + OK, + + /// + /// abort stream transfer + /// + Aborted, + + /// + /// Parameters are invalid + /// + InvalidParameter + } + + internal class StreamHelperResult + { + public StreamHelperResultCodes ResultCode; + + public long TransferedBytes; + } + + internal class StreamHelperProgressEvent : EventArgs + { + /// + /// Amount of bytes transfered in during this process + /// + public long ReadBytesTotal { get; set; } + + /// + /// Amount of bytes which has to be transfered in this process + /// + public long TotalLength { get; set; } + + /// + /// Amount of bytes transfered between this and the last event + /// + public long ReadBytesCurrentOperation { get; set; } + + /// + /// The transfer rate in KBits per Second related to bytes totally transfered (ReadBytesTotal) + /// + public long TransferRateTotal { get; set; } + + /// + /// The transfer rate in KBits per Second related to the last 500ms + /// + public long TransferRateCurrent { get; internal set; } + + /// + /// Overall progress in percent + /// + public int PercentageProgress + { + get + { + if (TotalLength == -1) + return -1; + if (TotalLength == 0) + return 100; + return (int)((100*ReadBytesTotal)/TotalLength); + } + } + } + + internal delegate StreamHelperResultCodes StreamHelperProgressCallback(object sender, StreamHelperProgressEvent e, params object[] data); + + internal class StreamHelper + { + private const int BufferSize = 4096; + + public static StreamHelperResult CopyStreamData(object sender, Stream src, Stream trg, StreamHelperProgressCallback status, params object[] data) + { + return CopyStreamData(sender, src, trg, -1, status, data); + } + + public static StreamHelperResult CopyStreamData(object sender, Stream src, Stream trg, long MaxSize, StreamHelperProgressCallback status, params object[] data) + { + // validate parameter + if (src == null || trg == null) + return new StreamHelperResult { ResultCode = StreamHelperResultCodes.InvalidParameter }; + + if (src.CanRead == false || trg.CanWrite == false) + return new StreamHelperResult { ResultCode = StreamHelperResultCodes.InvalidParameter }; + + // build the buffer as configured + var buffer = new byte[BufferSize]; + + // set the real buffer size + var RealBufferSize = BufferSize; + + // build the event for the status callback + var e = new StreamHelperProgressEvent(); + + // copy the stream data + int readBytes; + var readBytesTotal = 0; + var readBytes500msFrame = 0; + + var dtStart = DateTime.Now; + var dt500MsWatch = DateTime.Now; + var ts500MsWatch = new TimeSpan(); + + // set the total length if possible + try + { + e.TotalLength = src.Length; + } + catch (Exception) + { + if (MaxSize != -1) + e.TotalLength = MaxSize; + else + e.TotalLength = -1; + } + + if (MaxSize != -1 && e.TotalLength > MaxSize) + e.TotalLength = MaxSize; + + do + { + // Read the bytes + readBytes = src.Read(buffer, 0, RealBufferSize); + + // add + readBytesTotal += readBytes; + readBytes500msFrame += readBytes; + + // check for interuption + if (readBytes <= 0) + break; + + // Write the bytes + trg.Write(buffer, 0, readBytes); + + // notify state + if (status != null) + { + // upadte the event + e.ReadBytesTotal = readBytesTotal; + e.ReadBytesCurrentOperation = readBytes; + + // call the callback + var action = status(sender, e, data); + + // result + if (action == StreamHelperResultCodes.Aborted) + return new StreamHelperResult { ResultCode = StreamHelperResultCodes.Aborted, TransferedBytes = readBytesTotal }; + } + + // stop measurement + var dtLocalStop = DateTime.Now; + + // set the 500 ms span + ts500MsWatch = dtLocalStop - dt500MsWatch; + + // check if we achieved 500 ms + if (ts500MsWatch.TotalMilliseconds >= 500) + { + // update the current transfer rate + e.TransferRateCurrent = readBytes500msFrame/Convert.ToInt64(ts500MsWatch.TotalMilliseconds); + // bits per millisecond == kbits per second + e.TransferRateCurrent *= 8; + + // reset the bytes + readBytes500msFrame = 0; + + // reset the timespan + ts500MsWatch = new TimeSpan(); + + // reset the start timer + dt500MsWatch = DateTime.Now; + } + + // recalc the overall transfer rate + var consumedTimeAllOver = dtLocalStop - dtStart; + + if (Convert.ToInt64(consumedTimeAllOver.TotalMilliseconds) > 0) + { + // bytes per millisecond + e.TransferRateTotal = readBytesTotal/Convert.ToInt64(consumedTimeAllOver.TotalMilliseconds); + + // bits per millisecond == kbits per second + e.TransferRateTotal *= 8; + } + else + e.TransferRateTotal = -1; + + // check the max size + if (MaxSize != -1) + { + if (readBytesTotal >= MaxSize) + break; + + // check if we have to asjust the buffer size + if (MaxSize - readBytesTotal < RealBufferSize) + { + RealBufferSize = Convert.ToInt32(MaxSize - readBytesTotal); + } + } + + // check if we have + } while (readBytes > 0); + + return new StreamHelperResult { ResultCode = StreamHelperResultCodes.OK, TransferedBytes = readBytesTotal }; + } + + public static MemoryStream ToStream(string data) + { + // create the memory stream + var mStream = new MemoryStream(); + + // write the data into + var sw = new StreamWriter(mStream); + sw.Write(data); + sw.Flush(); + + // reset position + mStream.Position = 0; + + // go ahead + return mStream; + } + + public static TimeSpan CalculateOperationTransferTime(StreamHelperProgressEvent e) + { + // calc transfertime + if (e.TransferRateTotal != -1 && e.TransferRateTotal > 0) + { + var bytesPerSecond = (e.TransferRateTotal/8)*1000; + + if (bytesPerSecond > 0) + { + var neededSeconds = (e.TotalLength - e.ReadBytesTotal)/bytesPerSecond; + return new TimeSpan(neededSeconds*TimeSpan.TicksPerSecond); + } + + return new TimeSpan(long.MaxValue); + } + + return new TimeSpan(long.MaxValue); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpException.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpException.cs new file mode 100644 index 0000000000..c7ab3ba31d --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpException.cs @@ -0,0 +1,21 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net +{ + public class HttpException : Exception + { + private int _HttpCode; + + public HttpException(int httpCode, string message) + : base(message) + { + _HttpCode = httpCode; + } + + public int GetHttpCode() + { + return _HttpCode; + } + } +} diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtility.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtility.cs new file mode 100644 index 0000000000..59840ec8a5 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtility.cs @@ -0,0 +1,1214 @@ +namespace System.Net +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Globalization; + using System.IO; + using System.Text; + + /// + /// This class is a helper implementation for the Android platform + /// + internal sealed class HttpUtility + { + private static Hashtable entities; + private static char[] hexChars = "0123456789abcdef".ToCharArray(); + private static object lock_ = new object(); + + private static int GetChar(byte[] bytes, int offset, int length) + { + int num = 0; + int num2 = length + offset; + for (int i = offset; i < num2; i++) + { + int @int = GetInt(bytes[i]); + if (@int == -1) + { + return -1; + } + num = (num << 4) + @int; + } + return num; + } + + private static int GetChar(string str, int offset, int length) + { + int num = 0; + int num2 = length + offset; + for (int i = offset; i < num2; i++) + { + char ch = str[i]; + if (ch > '\x007f') + { + return -1; + } + int @int = GetInt((byte) ch); + if (@int == -1) + { + return -1; + } + num = (num << 4) + @int; + } + return num; + } + + private static char[] GetChars(MemoryStream b, Encoding e) + { + return e.GetChars(b.GetBuffer(), 0, (int) b.Length); + } + + private static int GetInt(byte b) + { + char ch = (char) b; + if ((ch >= '0') && (ch <= '9')) + { + return (ch - '0'); + } + if ((ch >= 'a') && (ch <= 'f')) + { + return ((ch - 'a') + 10); + } + if ((ch >= 'A') && (ch <= 'F')) + { + return ((ch - 'A') + 10); + } + return -1; + } + + public static string HtmlAttributeEncode(string s) + { + if (s == null) + { + return null; + } + bool flag = false; + for (int i = 0; i < s.Length; i++) + { + if (((s[i] == '&') || (s[i] == '"')) || (s[i] == '<')) + { + flag = true; + break; + } + } + if (!flag) + { + return s; + } + StringBuilder builder = new StringBuilder(); + int length = s.Length; + for (int j = 0; j < length; j++) + { + switch (s[j]) + { + case '"': + builder.Append("""); + break; + + case '&': + builder.Append("&"); + break; + + case '<': + builder.Append("<"); + break; + + default: + builder.Append(s[j]); + break; + } + } + return builder.ToString(); + } + + public static void HtmlAttributeEncode(string s, TextWriter output) + { + output.Write(HtmlAttributeEncode(s)); + } + + public static string HtmlDecode(string s) + { + if (s == null) + { + throw new ArgumentNullException("s"); + } + if (s.IndexOf('&') == -1) + { + return s; + } + StringBuilder builder = new StringBuilder(); + StringBuilder builder2 = new StringBuilder(); + int length = s.Length; + int num2 = 0; + int num3 = 0; + bool flag = false; + for (int i = 0; i < length; i++) + { + char ch = s[i]; + if (num2 == 0) + { + if (ch == '&') + { + builder.Append(ch); + num2 = 1; + } + else + { + builder2.Append(ch); + } + } + else if (ch == '&') + { + num2 = 1; + if (flag) + { + builder.Append(num3.ToString(CultureInfo.InvariantCulture)); + flag = false; + } + builder2.Append(builder.ToString()); + builder.Length = 0; + builder.Append('&'); + } + else + { + switch (num2) + { + case 1: + if (ch == ';') + { + num2 = 0; + builder2.Append(builder.ToString()); + builder2.Append(ch); + builder.Length = 0; + } + else + { + num3 = 0; + if (ch != '#') + { + num2 = 2; + } + else + { + num2 = 3; + } + builder.Append(ch); + } + break; + + case 2: + builder.Append(ch); + if (ch == ';') + { + string str = builder.ToString(); + if ((str.Length > 1) && Entities.ContainsKey(str.Substring(1, str.Length - 2))) + { + str = Entities[str.Substring(1, str.Length - 2)].ToString(); + } + builder2.Append(str); + num2 = 0; + builder.Length = 0; + } + break; + + case 3: + if (ch == ';') + { + if (num3 > 0xffff) + { + builder2.Append("&#"); + builder2.Append(num3.ToString(CultureInfo.InvariantCulture)); + builder2.Append(";"); + } + else + { + builder2.Append((char) num3); + } + num2 = 0; + builder.Length = 0; + flag = false; + } + else if (char.IsDigit(ch)) + { + num3 = (num3 * 10) + (ch - '0'); + flag = true; + } + else + { + num2 = 2; + if (flag) + { + builder.Append(num3.ToString(CultureInfo.InvariantCulture)); + flag = false; + } + builder.Append(ch); + } + break; + } + } + } + if (builder.Length > 0) + { + builder2.Append(builder.ToString()); + } + else if (flag) + { + builder2.Append(num3.ToString(CultureInfo.InvariantCulture)); + } + return builder2.ToString(); + } + + public static void HtmlDecode(string s, TextWriter output) + { + if (s != null) + { + output.Write(HtmlDecode(s)); + } + } + + public static string HtmlEncode(string s) + { + if (s == null) + { + return null; + } + bool flag = false; + for (int i = 0; i < s.Length; i++) + { + char ch = s[i]; + if (((ch == '&') || (ch == '"')) || (((ch == '<') || (ch == '>')) || (ch > '\x009f'))) + { + flag = true; + break; + } + } + if (!flag) + { + return s; + } + StringBuilder builder = new StringBuilder(); + int length = s.Length; + for (int j = 0; j < length; j++) + { + char ch2 = s[j]; + switch (ch2) + { + case '<': + { + builder.Append("<"); + continue; + } + case '>': + { + builder.Append(">"); + continue; + } + default: + { + if (ch2 != '"') + { + if (ch2 != '&') + { + goto Label_00F4; + } + builder.Append("&"); + } + else + { + builder.Append("""); + } + continue; + } + } + Label_00F4: + if (s[j] > '\x009f') + { + builder.Append("&#"); + builder.Append(((int) s[j]).ToString(CultureInfo.InvariantCulture)); + builder.Append(";"); + } + else + { + builder.Append(s[j]); + } + } + return builder.ToString(); + } + + public static void HtmlEncode(string s, TextWriter output) + { + if (s != null) + { + output.Write(HtmlEncode(s)); + } + } + + private static void InitEntities() + { + entities = new Hashtable(); + entities.Add("nbsp", '\x00a0'); + entities.Add("iexcl", '\x00a1'); + entities.Add("cent", '\x00a2'); + entities.Add("pound", '\x00a3'); + entities.Add("curren", '\x00a4'); + entities.Add("yen", '\x00a5'); + entities.Add("brvbar", '\x00a6'); + entities.Add("sect", '\x00a7'); + entities.Add("uml", '\x00a8'); + entities.Add("copy", '\x00a9'); + entities.Add("ordf", '\x00aa'); + entities.Add("laquo", '\x00ab'); + entities.Add("not", '\x00ac'); + entities.Add("shy", '\x00ad'); + entities.Add("reg", '\x00ae'); + entities.Add("macr", '\x00af'); + entities.Add("deg", '\x00b0'); + entities.Add("plusmn", '\x00b1'); + entities.Add("sup2", '\x00b2'); + entities.Add("sup3", '\x00b3'); + entities.Add("acute", '\x00b4'); + entities.Add("micro", '\x00b5'); + entities.Add("para", '\x00b6'); + entities.Add("middot", '\x00b7'); + entities.Add("cedil", '\x00b8'); + entities.Add("sup1", '\x00b9'); + entities.Add("ordm", '\x00ba'); + entities.Add("raquo", '\x00bb'); + entities.Add("frac14", '\x00bc'); + entities.Add("frac12", '\x00bd'); + entities.Add("frac34", '\x00be'); + entities.Add("iquest", '\x00bf'); + entities.Add("Agrave", '\x00c0'); + entities.Add("Aacute", '\x00c1'); + entities.Add("Acirc", '\x00c2'); + entities.Add("Atilde", '\x00c3'); + entities.Add("Auml", '\x00c4'); + entities.Add("Aring", '\x00c5'); + entities.Add("AElig", '\x00c6'); + entities.Add("Ccedil", '\x00c7'); + entities.Add("Egrave", '\x00c8'); + entities.Add("Eacute", '\x00c9'); + entities.Add("Ecirc", '\x00ca'); + entities.Add("Euml", '\x00cb'); + entities.Add("Igrave", '\x00cc'); + entities.Add("Iacute", '\x00cd'); + entities.Add("Icirc", '\x00ce'); + entities.Add("Iuml", '\x00cf'); + entities.Add("ETH", '\x00d0'); + entities.Add("Ntilde", '\x00d1'); + entities.Add("Ograve", '\x00d2'); + entities.Add("Oacute", '\x00d3'); + entities.Add("Ocirc", '\x00d4'); + entities.Add("Otilde", '\x00d5'); + entities.Add("Ouml", '\x00d6'); + entities.Add("times", '\x00d7'); + entities.Add("Oslash", '\x00d8'); + entities.Add("Ugrave", '\x00d9'); + entities.Add("Uacute", '\x00da'); + entities.Add("Ucirc", '\x00db'); + entities.Add("Uuml", '\x00dc'); + entities.Add("Yacute", '\x00dd'); + entities.Add("THORN", '\x00de'); + entities.Add("szlig", '\x00df'); + entities.Add("agrave", '\x00e0'); + entities.Add("aacute", '\x00e1'); + entities.Add("acirc", '\x00e2'); + entities.Add("atilde", '\x00e3'); + entities.Add("auml", '\x00e4'); + entities.Add("aring", '\x00e5'); + entities.Add("aelig", '\x00e6'); + entities.Add("ccedil", '\x00e7'); + entities.Add("egrave", '\x00e8'); + entities.Add("eacute", '\x00e9'); + entities.Add("ecirc", '\x00ea'); + entities.Add("euml", '\x00eb'); + entities.Add("igrave", '\x00ec'); + entities.Add("iacute", '\x00ed'); + entities.Add("icirc", '\x00ee'); + entities.Add("iuml", '\x00ef'); + entities.Add("eth", '\x00f0'); + entities.Add("ntilde", '\x00f1'); + entities.Add("ograve", '\x00f2'); + entities.Add("oacute", '\x00f3'); + entities.Add("ocirc", '\x00f4'); + entities.Add("otilde", '\x00f5'); + entities.Add("ouml", '\x00f6'); + entities.Add("divide", '\x00f7'); + entities.Add("oslash", '\x00f8'); + entities.Add("ugrave", '\x00f9'); + entities.Add("uacute", '\x00fa'); + entities.Add("ucirc", '\x00fb'); + entities.Add("uuml", '\x00fc'); + entities.Add("yacute", '\x00fd'); + entities.Add("thorn", '\x00fe'); + entities.Add("yuml", '\x00ff'); + entities.Add("fnof", 'ƒ'); + entities.Add("Alpha", 'Α'); + entities.Add("Beta", 'Β'); + entities.Add("Gamma", 'Γ'); + entities.Add("Delta", 'Δ'); + entities.Add("Epsilon", 'Ε'); + entities.Add("Zeta", 'Ζ'); + entities.Add("Eta", 'Η'); + entities.Add("Theta", 'Θ'); + entities.Add("Iota", 'Ι'); + entities.Add("Kappa", 'Κ'); + entities.Add("Lambda", 'Λ'); + entities.Add("Mu", 'Μ'); + entities.Add("Nu", 'Ν'); + entities.Add("Xi", 'Ξ'); + entities.Add("Omicron", 'Ο'); + entities.Add("Pi", 'Π'); + entities.Add("Rho", 'Ρ'); + entities.Add("Sigma", 'Σ'); + entities.Add("Tau", 'Τ'); + entities.Add("Upsilon", 'Υ'); + entities.Add("Phi", 'Φ'); + entities.Add("Chi", 'Χ'); + entities.Add("Psi", 'Ψ'); + entities.Add("Omega", 'Ω'); + entities.Add("alpha", 'α'); + entities.Add("beta", 'β'); + entities.Add("gamma", 'γ'); + entities.Add("delta", 'δ'); + entities.Add("epsilon", 'ε'); + entities.Add("zeta", 'ζ'); + entities.Add("eta", 'η'); + entities.Add("theta", 'θ'); + entities.Add("iota", 'ι'); + entities.Add("kappa", 'κ'); + entities.Add("lambda", 'λ'); + entities.Add("mu", 'μ'); + entities.Add("nu", 'ν'); + entities.Add("xi", 'ξ'); + entities.Add("omicron", 'ο'); + entities.Add("pi", 'π'); + entities.Add("rho", 'ρ'); + entities.Add("sigmaf", 'ς'); + entities.Add("sigma", 'σ'); + entities.Add("tau", 'τ'); + entities.Add("upsilon", 'υ'); + entities.Add("phi", 'φ'); + entities.Add("chi", 'χ'); + entities.Add("psi", 'ψ'); + entities.Add("omega", 'ω'); + entities.Add("thetasym", 'ϑ'); + entities.Add("upsih", 'ϒ'); + entities.Add("piv", 'ϖ'); + entities.Add("bull", '•'); + entities.Add("hellip", '…'); + entities.Add("prime", '′'); + entities.Add("Prime", '″'); + entities.Add("oline", '‾'); + entities.Add("frasl", '⁄'); + entities.Add("weierp", '℘'); + entities.Add("image", 'ℑ'); + entities.Add("real", 'ℜ'); + entities.Add("trade", '™'); + entities.Add("alefsym", 'ℵ'); + entities.Add("larr", '←'); + entities.Add("uarr", '↑'); + entities.Add("rarr", '→'); + entities.Add("darr", '↓'); + entities.Add("harr", '↔'); + entities.Add("crarr", '↵'); + entities.Add("lArr", '⇐'); + entities.Add("uArr", '⇑'); + entities.Add("rArr", '⇒'); + entities.Add("dArr", '⇓'); + entities.Add("hArr", '⇔'); + entities.Add("forall", '∀'); + entities.Add("part", '∂'); + entities.Add("exist", '∃'); + entities.Add("empty", '∅'); + entities.Add("nabla", '∇'); + entities.Add("isin", '∈'); + entities.Add("notin", '∉'); + entities.Add("ni", '∋'); + entities.Add("prod", '∏'); + entities.Add("sum", '∑'); + entities.Add("minus", '−'); + entities.Add("lowast", '∗'); + entities.Add("radic", '√'); + entities.Add("prop", '∝'); + entities.Add("infin", '∞'); + entities.Add("ang", '∠'); + entities.Add("and", '∧'); + entities.Add("or", '∨'); + entities.Add("cap", '∩'); + entities.Add("cup", '∪'); + entities.Add("int", '∫'); + entities.Add("there4", '∴'); + entities.Add("sim", '∼'); + entities.Add("cong", '≅'); + entities.Add("asymp", '≈'); + entities.Add("ne", '≠'); + entities.Add("equiv", '≡'); + entities.Add("le", '≤'); + entities.Add("ge", '≥'); + entities.Add("sub", '⊂'); + entities.Add("sup", '⊃'); + entities.Add("nsub", '⊄'); + entities.Add("sube", '⊆'); + entities.Add("supe", '⊇'); + entities.Add("oplus", '⊕'); + entities.Add("otimes", '⊗'); + entities.Add("perp", '⊥'); + entities.Add("sdot", '⋅'); + entities.Add("lceil", '⌈'); + entities.Add("rceil", '⌉'); + entities.Add("lfloor", '⌊'); + entities.Add("rfloor", '⌋'); + entities.Add("lang", '〈'); + entities.Add("rang", '〉'); + entities.Add("loz", '◊'); + entities.Add("spades", '♠'); + entities.Add("clubs", '♣'); + entities.Add("hearts", '♥'); + entities.Add("diams", '♦'); + entities.Add("quot", '"'); + entities.Add("amp", '&'); + entities.Add("lt", '<'); + entities.Add("gt", '>'); + entities.Add("OElig", 'Œ'); + entities.Add("oelig", 'œ'); + entities.Add("Scaron", 'Š'); + entities.Add("scaron", 'š'); + entities.Add("Yuml", 'Ÿ'); + entities.Add("circ", 'ˆ'); + entities.Add("tilde", '˜'); + entities.Add("ensp", ' '); + entities.Add("emsp", ' '); + entities.Add("thinsp", ' '); + entities.Add("zwnj", '‌'); + entities.Add("zwj", '‍'); + entities.Add("lrm", '‎'); + entities.Add("rlm", '‏'); + entities.Add("ndash", '–'); + entities.Add("mdash", '—'); + entities.Add("lsquo", '‘'); + entities.Add("rsquo", '’'); + entities.Add("sbquo", '‚'); + entities.Add("ldquo", '“'); + entities.Add("rdquo", '”'); + entities.Add("bdquo", '„'); + entities.Add("dagger", '†'); + entities.Add("Dagger", '‡'); + entities.Add("permil", '‰'); + entities.Add("lsaquo", '‹'); + entities.Add("rsaquo", '›'); + entities.Add("euro", '€'); + } + + private static bool NotEncoded(char c) + { + return (((((c == '!') || (c == '\'')) || ((c == '(') || (c == ')'))) || (((c == '*') || (c == '-')) || (c == '.'))) || (c == '_')); + } + + public static NameValueCollection ParseQueryString(string query) + { + return ParseQueryString(query, Encoding.UTF8); + } + + public static NameValueCollection ParseQueryString(string query, Encoding encoding) + { + if (query == null) + { + throw new ArgumentNullException("query"); + } + if (encoding == null) + { + throw new ArgumentNullException("encoding"); + } + if ((query.Length == 0) || ((query.Length == 1) && (query[0] == '?'))) + { + return new NameValueCollection(); + } + if (query[0] == '?') + { + query = query.Substring(1); + } + NameValueCollection result = new HttpQSCollection(); + ParseQueryString(query, encoding, result); + return result; + } + + internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result) + { + if (query.Length != 0) + { + string str = HtmlDecode(query); + int length = str.Length; + int startIndex = 0; + bool flag = true; + while (startIndex <= length) + { + string str2; + int num3 = -1; + int num4 = -1; + for (int i = startIndex; i < length; i++) + { + if ((num3 == -1) && (str[i] == '=')) + { + num3 = i + 1; + } + else if (str[i] == '&') + { + num4 = i; + break; + } + } + if (flag) + { + flag = false; + if (str[startIndex] == '?') + { + startIndex++; + } + } + if (num3 == -1) + { + str2 = null; + num3 = startIndex; + } + else + { + str2 = UrlDecode(str.Substring(startIndex, (num3 - startIndex) - 1), encoding); + } + if (num4 < 0) + { + startIndex = -1; + num4 = str.Length; + } + else + { + startIndex = num4 + 1; + } + string val = UrlDecode(str.Substring(num3, num4 - num3), encoding); + result.Add(str2, val); + if (startIndex == -1) + { + break; + } + } + } + } + + public static string UrlDecode(string str) + { + return UrlDecode(str, Encoding.UTF8); + } + + public static string UrlDecode(byte[] bytes, Encoding e) + { + if (bytes == null) + { + return null; + } + return UrlDecode(bytes, 0, bytes.Length, e); + } + + public static string UrlDecode(string s, Encoding e) + { + if (s == null) + { + return null; + } + if ((s.IndexOf('%') == -1) && (s.IndexOf('+') == -1)) + { + return s; + } + if (e == null) + { + e = Encoding.UTF8; + } + long length = s.Length; + List buf = new List(); + for (int i = 0; i < length; i++) + { + char ch = s[i]; + if (((ch == '%') && ((i + 2) < length)) && (s[i + 1] != '%')) + { + int num2; + if ((s[i + 1] == 'u') && ((i + 5) < length)) + { + num2 = GetChar(s, i + 2, 4); + if (num2 != -1) + { + WriteCharBytes(buf, (char) num2, e); + i += 5; + } + else + { + WriteCharBytes(buf, '%', e); + } + } + else + { + num2 = GetChar(s, i + 1, 2); + if (num2 != -1) + { + WriteCharBytes(buf, (char) num2, e); + i += 2; + } + else + { + WriteCharBytes(buf, '%', e); + } + } + } + else if (ch == '+') + { + WriteCharBytes(buf, ' ', e); + } + else + { + WriteCharBytes(buf, ch, e); + } + } + byte[] bytes = buf.ToArray(); + buf = null; + return e.GetString(bytes); + } + + public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e) + { + if (bytes == null) + { + return null; + } + if (count == 0) + { + return string.Empty; + } + if (bytes == null) + { + throw new ArgumentNullException("bytes"); + } + if ((offset < 0) || (offset > bytes.Length)) + { + throw new ArgumentOutOfRangeException("offset"); + } + if ((count < 0) || ((offset + count) > bytes.Length)) + { + throw new ArgumentOutOfRangeException("count"); + } + StringBuilder builder = new StringBuilder(); + MemoryStream b = new MemoryStream(); + int num = count + offset; + for (int i = offset; i < num; i++) + { + if (((bytes[i] == 0x25) && ((i + 2) < count)) && (bytes[i + 1] != 0x25)) + { + int num2; + if ((bytes[i + 1] == 0x75) && ((i + 5) < num)) + { + if (b.Length > 0L) + { + builder.Append(GetChars(b, e)); + b.SetLength(0L); + } + num2 = GetChar(bytes, i + 2, 4); + if (num2 == -1) + { + goto Label_0123; + } + builder.Append((char) num2); + i += 5; + continue; + } + num2 = GetChar(bytes, i + 1, 2); + if (num2 != -1) + { + b.WriteByte((byte) num2); + i += 2; + continue; + } + } + Label_0123: + if (b.Length > 0L) + { + builder.Append(GetChars(b, e)); + b.SetLength(0L); + } + if (bytes[i] == 0x2b) + { + builder.Append(' '); + } + else + { + builder.Append((char) bytes[i]); + } + } + if (b.Length > 0L) + { + builder.Append(GetChars(b, e)); + } + b = null; + return builder.ToString(); + } + + public static byte[] UrlDecodeToBytes(byte[] bytes) + { + if (bytes == null) + { + return null; + } + return UrlDecodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlDecodeToBytes(string str) + { + return UrlDecodeToBytes(str, Encoding.UTF8); + } + + public static byte[] UrlDecodeToBytes(string str, Encoding e) + { + if (str == null) + { + return null; + } + if (e == null) + { + throw new ArgumentNullException("e"); + } + return UrlDecodeToBytes(e.GetBytes(str)); + } + + public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count) + { + if (bytes == null) + { + return null; + } + if (count == 0) + { + return new byte[0]; + } + int length = bytes.Length; + if ((offset < 0) || (offset >= length)) + { + throw new ArgumentOutOfRangeException("offset"); + } + if ((count < 0) || (offset > (length - count))) + { + throw new ArgumentOutOfRangeException("count"); + } + MemoryStream stream = new MemoryStream(); + int num2 = offset + count; + for (int i = offset; i < num2; i++) + { + char ch = (char) bytes[i]; + if (ch == '+') + { + ch = ' '; + } + else if ((ch == '%') && (i < (num2 - 2))) + { + int num4 = GetChar(bytes, i + 1, 2); + if (num4 != -1) + { + ch = (char) num4; + i += 2; + } + } + stream.WriteByte((byte) ch); + } + return stream.ToArray(); + } + + public static string UrlEncode(string str) + { + return UrlEncode(str, Encoding.UTF8); + } + + public static string UrlEncode(byte[] bytes) + { + if (bytes == null) + { + return null; + } + if (bytes.Length == 0) + { + return string.Empty; + } + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length)); + } + + public static string UrlEncode(string s, Encoding Enc) + { + if (s == null) + { + return null; + } + if (s == string.Empty) + { + return string.Empty; + } + bool flag = false; + int length = s.Length; + for (int i = 0; i < length; i++) + { + char c = s[i]; + if (((((c < '0') || ((c < 'A') && (c > '9'))) || ((c > 'Z') && (c < 'a'))) || (c > 'z')) && !NotEncoded(c)) + { + flag = true; + break; + } + } + if (!flag) + { + return s; + } + byte[] bytes = new byte[Enc.GetMaxByteCount(s.Length)]; + int count = Enc.GetBytes(s, 0, s.Length, bytes, 0); + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, count)); + } + + public static string UrlEncode(byte[] bytes, int offset, int count) + { + if (bytes == null) + { + return null; + } + if (bytes.Length == 0) + { + return string.Empty; + } + return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count)); + } + + private static void UrlEncodeChar(char c, Stream result, bool isUnicode) + { + if (c > '\x00ff') + { + int num2 = c; + result.WriteByte(0x25); + result.WriteByte(0x75); + int index = num2 >> 12; + result.WriteByte((byte) hexChars[index]); + index = (num2 >> 8) & 15; + result.WriteByte((byte) hexChars[index]); + index = (num2 >> 4) & 15; + result.WriteByte((byte) hexChars[index]); + index = num2 & 15; + result.WriteByte((byte) hexChars[index]); + } + else if ((c > ' ') && NotEncoded(c)) + { + result.WriteByte((byte) c); + } + else if (c == ' ') + { + result.WriteByte(0x2b); + } + else if ((((c < '0') || ((c < 'A') && (c > '9'))) || ((c > 'Z') && (c < 'a'))) || (c > 'z')) + { + if (isUnicode && (c > '\x007f')) + { + result.WriteByte(0x25); + result.WriteByte(0x75); + result.WriteByte(0x30); + result.WriteByte(0x30); + } + else + { + result.WriteByte(0x25); + } + int num3 = c >> 4; + result.WriteByte((byte) hexChars[num3]); + num3 = c & '\x000f'; + result.WriteByte((byte) hexChars[num3]); + } + else + { + result.WriteByte((byte) c); + } + } + + public static byte[] UrlEncodeToBytes(byte[] bytes) + { + if (bytes == null) + { + return null; + } + if (bytes.Length == 0) + { + return new byte[0]; + } + return UrlEncodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlEncodeToBytes(string str) + { + return UrlEncodeToBytes(str, Encoding.UTF8); + } + + public static byte[] UrlEncodeToBytes(string str, Encoding e) + { + if (str == null) + { + return null; + } + if (str == string.Empty) + { + return new byte[0]; + } + byte[] bytes = e.GetBytes(str); + return UrlEncodeToBytes(bytes, 0, bytes.Length); + } + + public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count) + { + if (bytes == null) + { + return null; + } + int length = bytes.Length; + if (length == 0) + { + return new byte[0]; + } + if ((offset < 0) || (offset >= length)) + { + throw new ArgumentOutOfRangeException("offset"); + } + if ((count < 0) || (count > (length - offset))) + { + throw new ArgumentOutOfRangeException("count"); + } + MemoryStream result = new MemoryStream(count); + int num2 = offset + count; + for (int i = offset; i < num2; i++) + { + UrlEncodeChar((char) bytes[i], result, false); + } + return result.ToArray(); + } + + public static string UrlEncodeUnicode(string str) + { + if (str == null) + { + return null; + } + return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str)); + } + + public static byte[] UrlEncodeUnicodeToBytes(string str) + { + if (str == null) + { + return null; + } + if (str == string.Empty) + { + return new byte[0]; + } + MemoryStream result = new MemoryStream(str.Length); + foreach (char ch in str) + { + UrlEncodeChar(ch, result, true); + } + return result.ToArray(); + } + + public static string UrlPathEncode(string s) + { + if ((s == null) || (s.Length == 0)) + { + return s; + } + MemoryStream result = new MemoryStream(); + int length = s.Length; + for (int i = 0; i < length; i++) + { + UrlPathEncodeChar(s[i], result); + } + return Encoding.ASCII.GetString(result.ToArray()); + } + + private static void UrlPathEncodeChar(char c, Stream result) + { + if ((c < '!') || (c > '~')) + { + byte[] bytes = Encoding.UTF8.GetBytes(c.ToString()); + for (int i = 0; i < bytes.Length; i++) + { + result.WriteByte(0x25); + int index = bytes[i] >> 4; + result.WriteByte((byte) hexChars[index]); + index = bytes[i] & 15; + result.WriteByte((byte) hexChars[index]); + } + } + else if (c == ' ') + { + result.WriteByte(0x25); + result.WriteByte(50); + result.WriteByte(0x30); + } + else + { + result.WriteByte((byte) c); + } + } + + private static void WriteCharBytes(IList buf, char ch, Encoding e) + { + if (ch > '\x00ff') + { + char[] chars = new char[] { ch }; + foreach (byte num2 in e.GetBytes(chars)) + { + buf.Add(num2); + } + } + else + { + buf.Add((byte) ch); + } + } + + private static Hashtable Entities + { + get + { + object obj2 = lock_; + lock (obj2) + { + if (entities == null) + { + InitEntities(); + } + return entities; + } + } + } + + private sealed class HttpQSCollection : NameValueCollection + { + public override string ToString() + { + int count = this.Count; + if (count == 0) + { + return string.Empty; + } + StringBuilder builder = new StringBuilder(); + string[] allKeys = this.AllKeys; + for (int i = 0; i < count; i++) + { + builder.AppendFormat("{0}={1}&", allKeys[i], base[allKeys[i]]); + } + if (builder.Length > 0) + { + builder.Length--; + } + return builder.ToString(); + } + } + } +} + diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtilityEx.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtilityEx.cs new file mode 100644 index 0000000000..a8514b508d --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/HttpUtilityEx.cs @@ -0,0 +1,160 @@ +using System; +using System.Net; +using System.Text; + +using AppLimit.CloudComputing.SharpBox.Common.IO; + +using HttpUtility = System.Web.HttpUtility; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net +{ + /// + /// This class exposes some extensions to the .NET HttpUtility class + /// + public class HttpUtilityEx + { + /// + /// This method encodes an url + /// + /// + /// + public static string UrlEncodeUTF8(string text) + { + if (text == null) + return null; + + if (text.Length == 0) + return ""; + + // encode with url encoder + var enc = HttpUtility.UrlEncode(text, Encoding.UTF8); + + // fix the missing space + enc = enc.Replace("+", "%20"); + + // fix the exclamation point + enc = enc.Replace("!", "%21"); + + // fix the quote + enc = enc.Replace("'", "%27"); + + // fix the parentheses + enc = enc.Replace("(", "%28"); + enc = enc.Replace(")", "%29"); + + enc = enc.Replace("%2f", "/"); + + // uppercase the encoded stuff + var enc2 = new StringBuilder(); + + for (var i = 0; i < enc.Length; i++) + { + // copy char + enc2.Append(enc[i]); + + // upper stuff + if (enc[i] == '%') + { + enc2.Append(char.ToUpper(enc[i + 1])); + enc2.Append(char.ToUpper(enc[i + 2])); + + i += 2; + } + } + + return enc2.ToString(); + } + + /// + /// This methid decodes a UTF8 encoded path + /// + /// + /// + public static string PathDecodeUTF8(string text) + { + var output = string.Empty; + + if (text.StartsWith("/")) + output = "/"; + + var elements = text.Split('/'); + + foreach (var s in elements) + { + if (s == string.Empty) + continue; + + if (!output.EndsWith("/")) + output += "/"; + + // do the normal stuff + output += HttpUtility.UrlDecode(s); + } + + if (text.EndsWith("/")) + output += "/"; + + return output; + } + + /// + /// This method returns true if the give http error code is a success + /// error code, this means in 2XX + /// + /// + /// + public static bool IsSuccessCode(HttpStatusCode code) + { + return (((int)code >= 200 && (int)code < 300)); + } + + /// + /// This method returns true if the give http error code is a success + /// error code, this means in 2XX + /// + /// + /// + public static bool IsSuccessCode(int code) + { + return IsSuccessCode((HttpStatusCode)code); + } + + /// + /// This method generates a well encoded uri string + /// + /// + /// + public static string GenerateEncodedUriString(Uri uri) + { + // save the trailing / + var bTrailingSlash = uri.ToString().EndsWith("/"); + + // first part of string + var uriString = uri.Scheme + Uri.SchemeDelimiter + uri.Host + ":" + uri.Port; + + for (var i = 0; i < uri.Segments.Length; i++) + { + var partString = uri.Segments[i]; + partString = partString.TrimEnd('/'); + + uriString = PathHelper.Combine(uriString, partString); + } + + if (bTrailingSlash) + uriString += "/"; + + return uriString; + + } + + /// + /// Reduces the url to the root service url + /// + /// + /// + public static Uri GetPathAndQueryLessUri(Uri uri) + { + return new Uri(uri.Scheme + Uri.SchemeDelimiter + uri.DnsSafeHost + ":" + uri.Port); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonDateTimeConverter.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonDateTimeConverter.cs new file mode 100644 index 0000000000..cc2829a4ad --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonDateTimeConverter.cs @@ -0,0 +1,66 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Json +{ + /// + /// This class implements a json helper to convert a date time string + /// into the DateTime-Class of .NET + /// + internal class JsonDateTimeConverter + { + private enum Month + { + Jan = 1, + Feb, + Mar, + Apr, + May, + Jun, + Jul, + Aug, + Sep, + Oct, + Nov, + Dec + } + + private static Month ToMonth(string Input) + { + return (Month)Enum.Parse(typeof (Month), Input, true); + } + + /// + /// This method converts and returns a json date time string into a .NET date time + /// string + /// + /// The JSON datetime string + /// The .NET dateTime string + public static DateTime GetDateTimeProperty(string dateTime) + { + // Sat, 21 Aug 2010 22:31:20 +0000 + + // check1 + if (dateTime.Length == 0) + return DateTime.MinValue; + + // check2 + if (dateTime.Length != 31) + throw new InvalidOperationException(); + + // date + var day = dateTime.Substring(5, 2); + var month = dateTime.Substring(8, 3); + var m = ToMonth(month); + var year = dateTime.Substring(12, 4); + + // time + var hour = dateTime.Substring(17, 2); + var min = dateTime.Substring(20, 2); + var sec = dateTime.Substring(23, 2); + + return new DateTime(Convert.ToInt32(year), Convert.ToInt32(m), Convert.ToInt32(day), + Convert.ToInt32(hour), Convert.ToInt32(min), Convert.ToInt32(sec), + DateTimeKind.Utc); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonHelper.cs new file mode 100644 index 0000000000..904a6dc2a1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Json/JsonHelper.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +using Newtonsoft.Json.Linq; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Json +{ + internal class JsonHelper + { + private JToken _tokenInfo; + + public bool ParseJsonMessage(string jsonmsg) + { + _tokenInfo = JObject.Parse(jsonmsg); + + return true; + } + + public string GetProperty(string key) + { + var val = Convert.ToString(_tokenInfo.SelectToken(key)); + return val.Replace("\"", ""); + } + + public List GetListProperty(string key) + { + var lstRet = new List(); + + var childs = _tokenInfo.SelectToken(key) as JArray; + if (childs == null || childs.Count <= 0) + return lstRet; + + foreach (var child in (IEnumerable)childs) + { + lstRet.Add(child.ToString()); + } + + return lstRet; + } + + public bool GetBooleanProperty(string key) + { + var bv = _tokenInfo.SelectToken(key); + if (bv == null) + return false; + + var trueValue = new JValue(true); + return trueValue.Equals(bv); + } + + public string GetSubObjectString(string key) + { + var data = _tokenInfo.SelectToken(key); + if (data != null) + return data.ToString(); + return ""; + } + + public int GetPropertyInt(string key) + { + return Convert.ToInt32(GetProperty(key)); + } + + public DateTime GetDateTimeProperty(string key) + { + // read the string + var dateTime = GetProperty(key).Trim(); + + // convert + return JsonDateTimeConverter.GetDateTimeProperty(dateTime); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/MimeMapping.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/MimeMapping.cs new file mode 100644 index 0000000000..c91b54aebc --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/MimeMapping.cs @@ -0,0 +1,916 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net +{ + public static class MimeMapping + { + private static readonly Hashtable ExtensionToMimeMappingTable = new Hashtable(200, + StringComparer. + CurrentCultureIgnoreCase); + + private static readonly IDictionary> MimeSynonyms = + new Dictionary>(); + + static MimeMapping() + { + AddMimeMapping(".3dm", "x-world/x-3dmf"); + AddMimeMapping(".3dmf", "x-world/x-3dmf"); + AddMimeMapping(".a", "application/octet-stream"); + AddMimeMapping(".aab", "application/x-authorware-bin"); + AddMimeMapping(".aam", "application/x-authorware-map"); + AddMimeMapping(".aas", "application/x-authorware-seg"); + AddMimeMapping(".abc", "text/vnd.abc"); + AddMimeMapping(".acgi", "text/html"); + AddMimeMapping(".afl", "video/animaflex"); + AddMimeMapping(".ai", "application/postscript"); + AddMimeMapping(".aif", "audio/aiff"); + AddMimeMapping(".aif", "audio/x-aiff"); + AddMimeMapping(".aifc", "audio/aiff"); + AddMimeMapping(".aifc", "audio/x-aiff"); + AddMimeMapping(".aiff", "audio/aiff"); + AddMimeMapping(".aiff", "audio/x-aiff"); + AddMimeMapping(".aim", "application/x-aim"); + AddMimeMapping(".aip", "text/x-audiosoft-intra"); + AddMimeMapping(".ani", "application/x-navi-animation"); + AddMimeMapping(".aos", "application/x-nokia-9000-communicator-add-on-software"); + AddMimeMapping(".aps", "application/mime"); + AddMimeMapping(".arc", "application/octet-stream"); + AddMimeMapping(".arj", "application/arj"); + AddMimeMapping(".arj", "application/octet-stream"); + AddMimeMapping(".art", "image/x-jg"); + AddMimeMapping(".asf", "video/x-ms-asf"); + AddMimeMapping(".asm", "text/x-asm"); + AddMimeMapping(".asp", "text/asp"); + AddMimeMapping(".asx", "application/x-mplayer2"); + AddMimeMapping(".asx", "video/x-ms-asf"); + AddMimeMapping(".asx", "video/x-ms-asf-plugin"); + AddMimeMapping(".au", "audio/basic"); + AddMimeMapping(".au", "audio/x-au"); + AddMimeMapping(".avi", "video/avi"); + AddMimeMapping(".avi", "application/x-troff-msvideo"); + AddMimeMapping(".avi", "video/msvideo"); + AddMimeMapping(".avi", "video/x-msvideo"); + AddMimeMapping(".avs", "video/avs-video"); + AddMimeMapping(".bcpio", "application/x-bcpio"); + AddMimeMapping(".bin", "application/octet-stream"); + AddMimeMapping(".bin", "application/mac-binary"); + AddMimeMapping(".bin", "application/macbinary"); + AddMimeMapping(".bin", "application/x-binary"); + AddMimeMapping(".bin", "application/x-macbinary"); + AddMimeMapping(".bm", "image/bmp"); + AddMimeMapping(".bmp", "image/bmp"); + AddMimeMapping(".bmp", "image/x-windows-bmp"); + AddMimeMapping(".bmp", "image/x-ms-bmp"); + AddMimeMapping(".boo", "application/book"); + AddMimeMapping(".book", "application/book"); + AddMimeMapping(".boz", "application/x-bzip2"); + AddMimeMapping(".bsh", "application/x-bsh"); + AddMimeMapping(".bz", "application/x-bzip"); + AddMimeMapping(".bz2", "application/x-bzip2"); + AddMimeMapping(".c", "text/plain"); + AddMimeMapping(".c", "text/x-c"); + AddMimeMapping(".c++", "text/plain"); + AddMimeMapping(".cat", "application/vnd.ms-pki.seccat"); + AddMimeMapping(".cc", "text/plain"); + AddMimeMapping(".cc", "text/x-c"); + AddMimeMapping(".ccad", "application/clariscad"); + AddMimeMapping(".cco", "application/x-cocoa"); + AddMimeMapping(".cdf", "application/cdf"); + AddMimeMapping(".cdf", "application/x-cdf"); + AddMimeMapping(".cdf", "application/x-netcdf"); + AddMimeMapping(".cer", "application/pkix-cert"); + AddMimeMapping(".cer", "application/x-x509-ca-cert"); + AddMimeMapping(".cha", "application/x-chat"); + AddMimeMapping(".chat", "application/x-chat"); + AddMimeMapping(".class", "application/java"); + AddMimeMapping(".class", "application/java-byte-code"); + AddMimeMapping(".class", "application/x-java-class"); + AddMimeMapping(".com", "application/octet-stream"); + AddMimeMapping(".com", "text/plain"); + AddMimeMapping(".conf", "text/plain"); + AddMimeMapping(".cpio", "application/x-cpio"); + AddMimeMapping(".cpp", "text/x-c"); + AddMimeMapping(".cpt", "application/mac-compactpro"); + AddMimeMapping(".cpt", "application/x-compactpro"); + AddMimeMapping(".cpt", "application/x-cpt"); + AddMimeMapping(".crl", "application/pkcs-crl"); + AddMimeMapping(".crl", "application/pkix-crl"); + AddMimeMapping(".crt", "application/pkix-cert"); + AddMimeMapping(".crt", "application/x-x509-ca-cert"); + AddMimeMapping(".crt", "application/x-x509-user-cert"); + AddMimeMapping(".csh", "application/x-csh"); + AddMimeMapping(".csh", "text/x-script.csh"); + AddMimeMapping(".css", "text/css"); + AddMimeMapping(".css", "application/x-pointplus"); + AddMimeMapping(".cxx", "text/plain"); + AddMimeMapping(".dcr", "application/x-director"); + AddMimeMapping(".deepv", "application/x-deepv"); + AddMimeMapping(".def", "text/plain"); + AddMimeMapping(".der", "application/x-x509-ca-cert"); + AddMimeMapping(".dif", "video/x-dv"); + AddMimeMapping(".dir", "application/x-director"); + AddMimeMapping(".dll", "application/octet-stream"); + AddMimeMapping(".dl", "video/dl"); + AddMimeMapping(".dl", "video/x-dl"); + AddMimeMapping(".doc", "application/msword"); + AddMimeMapping(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + AddMimeMapping(".dot", "application/msword"); + AddMimeMapping(".dp", "application/commonground"); + AddMimeMapping(".drw", "application/drafting"); + AddMimeMapping(".dump", "application/octet-stream"); + AddMimeMapping(".dv", "video/x-dv"); + AddMimeMapping(".dvi", "application/x-dvi"); + AddMimeMapping(".dwf", "drawing/x-dwf (old)"); + AddMimeMapping(".dwf", "model/vnd.dwf"); + AddMimeMapping(".dwg", "application/acad"); + AddMimeMapping(".dwg", "image/vnd.dwg"); + AddMimeMapping(".dwg", "image/x-dwg"); + AddMimeMapping(".dxf", "application/dxf"); + AddMimeMapping(".dxf", "image/vnd.dwg"); + AddMimeMapping(".dxf", "image/x-dwg"); + AddMimeMapping(".dxr", "application/x-director"); + AddMimeMapping(".el", "text/x-script.elisp"); + AddMimeMapping(".elc", "application/x-bytecode.elisp (compiled elisp)"); + AddMimeMapping(".elc", "application/x-elc"); + AddMimeMapping(".env", "application/x-envoy"); + AddMimeMapping(".eps", "application/postscript"); + AddMimeMapping(".es", "application/x-esrehber"); + AddMimeMapping(".etx", "text/x-setext"); + AddMimeMapping(".evy", "application/envoy"); + AddMimeMapping(".evy", "application/x-envoy"); + AddMimeMapping(".exe", "application/octet-stream"); + AddMimeMapping(".f", "text/plain"); + AddMimeMapping(".f", "text/x-fortran"); + AddMimeMapping(".f77", "text/x-fortran"); + AddMimeMapping(".f90", "text/plain"); + AddMimeMapping(".f90", "text/x-fortran"); + AddMimeMapping(".fdf", "application/vnd.fdf"); + AddMimeMapping(".fif", "application/fractals"); + AddMimeMapping(".fif", "image/fif"); + AddMimeMapping(".fli", "video/fli"); + AddMimeMapping(".fli", "video/x-fli"); + AddMimeMapping(".flo", "image/florian"); + AddMimeMapping(".flx", "text/vnd.fmi.flexstor"); + AddMimeMapping(".fmf", "video/x-atomic3d-feature"); + AddMimeMapping(".for", "text/plain"); + AddMimeMapping(".for", "text/x-fortran"); + AddMimeMapping(".fpx", "image/vnd.fpx"); + AddMimeMapping(".fpx", "image/vnd.net-fpx"); + AddMimeMapping(".frl", "application/freeloader"); + AddMimeMapping(".funk", "audio/make"); + AddMimeMapping(".g", "text/plain"); + AddMimeMapping(".g3", "image/g3fax"); + AddMimeMapping(".gif", "image/gif"); + AddMimeMapping(".gl", "video/gl"); + AddMimeMapping(".gl", "video/x-gl"); + AddMimeMapping(".gsd", "audio/x-gsm"); + AddMimeMapping(".gsm", "audio/x-gsm"); + AddMimeMapping(".gsp", "application/x-gsp"); + AddMimeMapping(".gss", "application/x-gss"); + AddMimeMapping(".gtar", "application/x-gtar"); + AddMimeMapping(".gz", "application/x-gzip"); + AddMimeMapping(".gz", "application/x-compressed"); + AddMimeMapping(".gzip", "application/x-gzip"); + AddMimeMapping(".gzip", "multipart/x-gzip"); + AddMimeMapping(".h", "text/plain"); + AddMimeMapping(".h", "text/x-h"); + AddMimeMapping(".hdf", "application/x-hdf"); + AddMimeMapping(".help", "application/x-helpfile"); + AddMimeMapping(".hgl", "application/vnd.hp-hpgl"); + AddMimeMapping(".hh", "text/plain"); + AddMimeMapping(".hh", "text/x-h"); + AddMimeMapping(".hlb", "text/x-script"); + AddMimeMapping(".hlp", "application/hlp"); + AddMimeMapping(".hlp", "application/x-helpfile"); + AddMimeMapping(".hlp", "application/x-winhelp"); + AddMimeMapping(".hpg", "application/vnd.hp-hpgl"); + AddMimeMapping(".hpgl", "application/vnd.hp-hpgl"); + AddMimeMapping(".hqx", "application/binhex"); + AddMimeMapping(".hqx", "application/binhex4"); + AddMimeMapping(".hqx", "application/mac-binhex"); + AddMimeMapping(".hqx", "application/mac-binhex40"); + AddMimeMapping(".hqx", "application/x-binhex40"); + AddMimeMapping(".hqx", "application/x-mac-binhex40"); + AddMimeMapping(".hta", "application/hta"); + AddMimeMapping(".htc", "text/x-component"); + AddMimeMapping(".htm", "text/html"); + AddMimeMapping(".html", "text/html"); + AddMimeMapping(".htmls", "text/html"); + AddMimeMapping(".htt", "text/webviewhtml"); + AddMimeMapping(".htx", "text/html"); + AddMimeMapping(".ice", "x-conference/x-cooltalk"); + AddMimeMapping(".ico", "image/x-icon"); + AddMimeMapping(".idc", "text/plain"); + AddMimeMapping(".ief", "image/ief"); + AddMimeMapping(".iefs", "image/ief"); + AddMimeMapping(".iges", "application/iges"); + AddMimeMapping(".iges", "model/iges"); + AddMimeMapping(".igs", "application/iges"); + AddMimeMapping(".igs", "model/iges"); + AddMimeMapping(".ima", "application/x-ima"); + AddMimeMapping(".imap", "application/x-httpd-imap"); + AddMimeMapping(".inf", "application/inf"); + AddMimeMapping(".ins", "application/x-internett-signup"); + AddMimeMapping(".ip", "application/x-ip2"); + AddMimeMapping(".isu", "video/x-isvideo"); + AddMimeMapping(".it", "audio/it"); + AddMimeMapping(".iv", "application/x-inventor"); + AddMimeMapping(".ivr", "i-world/i-vrml"); + AddMimeMapping(".ivy", "application/x-livescreen"); + AddMimeMapping(".jam", "audio/x-jam"); + AddMimeMapping(".jav", "text/plain"); + AddMimeMapping(".jav", "text/x-java-source"); + AddMimeMapping(".java", "text/plain"); + AddMimeMapping(".java", "text/x-java-source"); + AddMimeMapping(".jcm", "application/x-java-commerce"); + AddMimeMapping(".jfif", "image/jpeg"); + AddMimeMapping(".jfif", "image/pjpeg"); + AddMimeMapping(".jfif-tbnl", "image/jpeg"); + AddMimeMapping(".jpeg", "image/jpeg"); + AddMimeMapping(".jpe", "image/jpeg"); + AddMimeMapping(".jpe", "image/pjpeg"); + AddMimeMapping(".jpeg", "image/pjpeg"); + AddMimeMapping(".jpg", "image/jpeg"); + AddMimeMapping(".jpg", "image/pjpeg"); + AddMimeMapping(".jps", "image/x-jps"); + AddMimeMapping(".json", "application/json"); + AddMimeMapping(".js", "text/javascript"); + AddMimeMapping(".js", "application/javascript"); + AddMimeMapping(".js", "application/x-javascript"); + AddMimeMapping(".js", "application/ecmascript"); + AddMimeMapping(".js", "text/ecmascript"); + AddMimeMapping(".jut", "image/jutvision"); + AddMimeMapping(".kar", "audio/midi"); + AddMimeMapping(".kar", "music/x-karaoke"); + AddMimeMapping(".ksh", "application/x-ksh"); + AddMimeMapping(".ksh", "text/x-script.ksh"); + AddMimeMapping(".la", "audio/nspaudio"); + AddMimeMapping(".la", "audio/x-nspaudio"); + AddMimeMapping(".lam", "audio/x-liveaudio"); + AddMimeMapping(".latex", "application/x-latex"); + AddMimeMapping(".less", "text/css"); + AddMimeMapping(".lha", "application/lha"); + AddMimeMapping(".lha", "application/octet-stream"); + AddMimeMapping(".lha", "application/x-lha"); + AddMimeMapping(".lhx", "application/octet-stream"); + AddMimeMapping(".list", "text/plain"); + AddMimeMapping(".lma", "audio/nspaudio"); + AddMimeMapping(".lma", "audio/x-nspaudio"); + AddMimeMapping(".log", "text/plain"); + AddMimeMapping(".lsp", "application/x-lisp"); + AddMimeMapping(".lsp", "text/x-script.lisp"); + AddMimeMapping(".lst", "text/plain"); + AddMimeMapping(".lsx", "text/x-la-asf"); + AddMimeMapping(".ltx", "application/x-latex"); + AddMimeMapping(".lzh", "application/octet-stream"); + AddMimeMapping(".lzh", "application/x-lzh"); + AddMimeMapping(".lzx", "application/lzx"); + AddMimeMapping(".lzx", "application/octet-stream"); + AddMimeMapping(".lzx", "application/x-lzx"); + AddMimeMapping(".m", "text/plain"); + AddMimeMapping(".m", "text/x-m"); + AddMimeMapping(".m1v", "video/mpeg"); + AddMimeMapping(".m2a", "audio/mpeg"); + AddMimeMapping(".m2v", "video/mpeg"); + AddMimeMapping(".m3u", "audio/x-mpequrl"); + AddMimeMapping(".man", "application/x-troff-man"); + AddMimeMapping(".map", "application/x-navimap"); + AddMimeMapping(".mar", "text/plain"); + AddMimeMapping(".mbd", "application/mbedlet"); + AddMimeMapping(".mc$", "application/x-magic-cap-package-1.0"); + AddMimeMapping(".mcd", "application/mcad"); + AddMimeMapping(".mcd", "application/x-mathcad"); + AddMimeMapping(".mcf", "image/vasa"); + AddMimeMapping(".mcf", "text/mcf"); + AddMimeMapping(".mcp", "application/netmc"); + AddMimeMapping(".me", "application/x-troff-me"); + AddMimeMapping(".mht", "message/rfc822"); + AddMimeMapping(".mhtml", "message/rfc822"); + AddMimeMapping(".mid", "application/x-midi"); + AddMimeMapping(".mid", "audio/midi"); + AddMimeMapping(".mid", "audio/x-mid"); + AddMimeMapping(".mid", "audio/x-midi"); + AddMimeMapping(".mid", "music/crescendo"); + AddMimeMapping(".mid", "x-music/x-midi"); + AddMimeMapping(".midi", "application/x-midi"); + AddMimeMapping(".midi", "audio/midi"); + AddMimeMapping(".midi", "audio/x-mid"); + AddMimeMapping(".midi", "audio/x-midi"); + AddMimeMapping(".midi", "music/crescendo"); + AddMimeMapping(".midi", "x-music/x-midi"); + AddMimeMapping(".mif", "application/x-frame"); + AddMimeMapping(".mif", "application/x-mif"); + AddMimeMapping(".mime", "message/rfc822"); + AddMimeMapping(".mime", "www/mime"); + AddMimeMapping(".mjf", "audio/x-vnd.audioexplosion.mjuicemediafile"); + AddMimeMapping(".mjpg", "video/x-motion-jpeg"); + AddMimeMapping(".mm", "application/base64"); + AddMimeMapping(".mm", "application/x-meme"); + AddMimeMapping(".mme", "application/base64"); + AddMimeMapping(".mod", "audio/mod"); + AddMimeMapping(".mod", "audio/x-mod"); + AddMimeMapping(".moov", "video/quicktime"); + AddMimeMapping(".mov", "video/quicktime"); + AddMimeMapping(".movie", "video/x-sgi-movie"); + AddMimeMapping(".mp2", "audio/mpeg"); + AddMimeMapping(".mp2", "audio/x-mpeg"); + AddMimeMapping(".mp2", "video/mpeg"); + AddMimeMapping(".mp2", "video/x-mpeg"); + AddMimeMapping(".mp2", "video/x-mpeq2a"); + AddMimeMapping(".mp3", "audio/mpeg3"); + AddMimeMapping(".mp3", "audio/x-mpeg-3"); + AddMimeMapping(".mp3", "video/mpeg"); + AddMimeMapping(".mp3", "video/x-mpeg"); + AddMimeMapping(".mpa", "audio/mpeg"); + AddMimeMapping(".mpa", "video/mpeg"); + AddMimeMapping(".mpc", "application/x-project"); + AddMimeMapping(".mpe", "video/mpeg"); + AddMimeMapping(".mpeg", "video/mpeg"); + AddMimeMapping(".mpg", "audio/mpeg"); + AddMimeMapping(".mpg", "video/mpeg"); + AddMimeMapping(".mpga", "audio/mpeg"); + AddMimeMapping(".mpp", "application/vnd.ms-project"); + AddMimeMapping(".mpt", "application/x-project"); + AddMimeMapping(".mpv", "application/x-project"); + AddMimeMapping(".mpx", "application/x-project"); + AddMimeMapping(".mrc", "application/marc"); + AddMimeMapping(".ms", "application/x-troff-ms"); + AddMimeMapping(".mv", "video/x-sgi-movie"); + AddMimeMapping(".my", "audio/make"); + AddMimeMapping(".mzz", "application/x-vnd.audioexplosion.mzz"); + AddMimeMapping(".nap", "image/naplps"); + AddMimeMapping(".naplps", "image/naplps"); + AddMimeMapping(".nc", "application/x-netcdf"); + AddMimeMapping(".ncm", "application/vnd.nokia.configuration-message"); + AddMimeMapping(".nif", "image/x-niff"); + AddMimeMapping(".niff", "image/x-niff"); + AddMimeMapping(".nix", "application/x-mix-transfer"); + AddMimeMapping(".nsc", "application/x-conference"); + AddMimeMapping(".nvd", "application/x-navidoc"); + AddMimeMapping(".o", "application/octet-stream"); + AddMimeMapping(".oda", "application/oda"); + AddMimeMapping(".omc", "application/x-omc"); + AddMimeMapping(".omcd", "application/x-omcdatamaker"); + AddMimeMapping(".omcr", "application/x-omcregerator"); + AddMimeMapping(".p", "text/x-pascal"); + AddMimeMapping(".p10", "application/pkcs10"); + AddMimeMapping(".p10", "application/x-pkcs10"); + AddMimeMapping(".p12", "application/pkcs-12"); + AddMimeMapping(".p12", "application/x-pkcs12"); + AddMimeMapping(".p7a", "application/x-pkcs7-signature"); + AddMimeMapping(".p7c", "application/pkcs7-mime"); + AddMimeMapping(".p7c", "application/x-pkcs7-mime"); + AddMimeMapping(".p7m", "application/pkcs7-mime"); + AddMimeMapping(".p7m", "application/x-pkcs7-mime"); + AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp"); + AddMimeMapping(".p7s", "application/pkcs7-signature"); + AddMimeMapping(".part", "application/pro_eng"); + AddMimeMapping(".pas", "text/pascal"); + AddMimeMapping(".pbm", "image/x-portable-bitmap"); + AddMimeMapping(".pcl", "application/vnd.hp-pcl"); + AddMimeMapping(".pcl", "application/x-pcl"); + AddMimeMapping(".pct", "image/x-pict"); + AddMimeMapping(".pcx", "image/x-pcx"); + AddMimeMapping(".pdb", "chemical/x-pdb"); + AddMimeMapping(".pdf", "application/pdf"); + AddMimeMapping(".pfunk", "audio/make"); + AddMimeMapping(".pfunk", "audio/make.my.funk"); + AddMimeMapping(".pgm", "image/x-portable-graymap"); + AddMimeMapping(".pgm", "image/x-portable-greymap"); + AddMimeMapping(".pic", "image/pict"); + AddMimeMapping(".pict", "image/pict"); + AddMimeMapping(".pkg", "application/x-newton-compatible-pkg"); + AddMimeMapping(".pko", "application/vnd.ms-pki.pko"); + AddMimeMapping(".pl", "text/plain"); + AddMimeMapping(".pl", "text/x-script.perl"); + AddMimeMapping(".plx", "application/x-pixclscript"); + AddMimeMapping(".pm", "image/x-xpixmap"); + AddMimeMapping(".pm", "text/x-script.perl-module"); + AddMimeMapping(".pm4", "application/x-pagemaker"); + AddMimeMapping(".pm5", "application/x-pagemaker"); + AddMimeMapping(".png", "image/png"); + AddMimeMapping(".pnm", "application/x-portable-anymap"); + AddMimeMapping(".pnm", "image/x-portable-anymap"); + AddMimeMapping(".pot", "application/mspowerpoint"); + AddMimeMapping(".pot", "application/vnd.ms-powerpoint"); + AddMimeMapping(".pov", "model/x-pov"); + AddMimeMapping(".ppa", "application/vnd.ms-powerpoint"); + AddMimeMapping(".ppm", "image/x-portable-pixmap"); + AddMimeMapping(".pps", "application/mspowerpoint"); + AddMimeMapping(".pps", "application/vnd.ms-powerpoint"); + AddMimeMapping(".ppt", "application/vnd.ms-powerpoint"); + AddMimeMapping(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); + AddMimeMapping(".ppz", "application/mspowerpoint"); + AddMimeMapping(".pre", "application/x-freelance"); + AddMimeMapping(".prt", "application/pro_eng"); + AddMimeMapping(".ps", "application/postscript"); + AddMimeMapping(".psd", "application/octet-stream"); + AddMimeMapping(".pvu", "paleovu/x-pv"); + AddMimeMapping(".pwz", "application/vnd.ms-powerpoint"); + AddMimeMapping(".py", "text/x-script.phyton"); + AddMimeMapping(".pyc", "applicaiton/x-bytecode.python"); + AddMimeMapping(".qcp", "audio/vnd.qcelp"); + AddMimeMapping(".qd3", "x-world/x-3dmf"); + AddMimeMapping(".qd3d", "x-world/x-3dmf"); + AddMimeMapping(".qif", "image/x-quicktime"); + AddMimeMapping(".qt", "video/quicktime"); + AddMimeMapping(".qtc", "video/x-qtc"); + AddMimeMapping(".qti", "image/x-quicktime"); + AddMimeMapping(".qtif", "image/x-quicktime"); + AddMimeMapping(".ra", "audio/x-pn-realaudio"); + AddMimeMapping(".ra", "audio/x-pn-realaudio-plugin"); + AddMimeMapping(".ra", "audio/x-realaudio"); + AddMimeMapping(".ram", "audio/x-pn-realaudio"); + AddMimeMapping(".ras", "application/x-cmu-raster"); + AddMimeMapping(".ras", "image/cmu-raster"); + AddMimeMapping(".ras", "image/x-cmu-raster"); + AddMimeMapping(".rast", "image/cmu-raster"); + AddMimeMapping(".rexx", "text/x-script.rexx"); + AddMimeMapping(".rf", "image/vnd.rn-realflash"); + AddMimeMapping(".rgb", "image/x-rgb"); + AddMimeMapping(".rm", "application/vnd.rn-realmedia"); + AddMimeMapping(".rm", "audio/x-pn-realaudio"); + AddMimeMapping(".rmi", "audio/mid"); + AddMimeMapping(".rmm", "audio/x-pn-realaudio"); + AddMimeMapping(".rmp", "audio/x-pn-realaudio"); + AddMimeMapping(".rmp", "audio/x-pn-realaudio-plugin"); + AddMimeMapping(".rng", "application/ringing-tones"); + AddMimeMapping(".rng", "application/vnd.nokia.ringing-tone"); + AddMimeMapping(".rnx", "application/vnd.rn-realplayer"); + AddMimeMapping(".roff", "application/x-troff"); + AddMimeMapping(".rp", "image/vnd.rn-realpix"); + AddMimeMapping(".rpm", "audio/x-pn-realaudio-plugin"); + AddMimeMapping(".rt", "text/richtext"); + AddMimeMapping(".rt", "text/vnd.rn-realtext"); + AddMimeMapping(".rtf", "application/rtf"); + AddMimeMapping(".rtf", "application/x-rtf"); + AddMimeMapping(".rtf", "text/richtext"); + AddMimeMapping(".rtx", "application/rtf"); + AddMimeMapping(".rtx", "text/richtext"); + AddMimeMapping(".rv", "video/vnd.rn-realvideo"); + AddMimeMapping(".s", "text/x-asm"); + AddMimeMapping(".s3m", "audio/s3m"); + AddMimeMapping(".saveme", "application/octet-stream"); + AddMimeMapping(".sbk", "application/x-tbook"); + AddMimeMapping(".scm", "application/x-lotusscreencam"); + AddMimeMapping(".scm", "text/x-script.guile"); + AddMimeMapping(".scm", "text/x-script.scheme"); + AddMimeMapping(".scm", "video/x-scm"); + AddMimeMapping(".sdml", "text/plain"); + AddMimeMapping(".sdp", "application/sdp"); + AddMimeMapping(".sdp", "application/x-sdp"); + AddMimeMapping(".sdr", "application/sounder"); + AddMimeMapping(".sea", "application/sea"); + AddMimeMapping(".sea", "application/x-sea"); + AddMimeMapping(".set", "application/set"); + AddMimeMapping(".sgm", "text/sgml"); + AddMimeMapping(".sgm", "text/x-sgml"); + AddMimeMapping(".sgml", "text/sgml"); + AddMimeMapping(".sgml", "text/x-sgml"); + AddMimeMapping(".sh", "application/x-bsh"); + AddMimeMapping(".sh", "application/x-sh"); + AddMimeMapping(".sh", "application/x-shar"); + AddMimeMapping(".sh", "text/x-script.sh"); + AddMimeMapping(".shar", "application/x-bsh"); + AddMimeMapping(".shar", "application/x-shar"); + AddMimeMapping(".shtml", "text/html"); + AddMimeMapping(".shtml", "text/x-server-parsed-html"); + AddMimeMapping(".sid", "audio/x-psid"); + AddMimeMapping(".sit", "application/x-sit"); + AddMimeMapping(".sit", "application/x-stuffit"); + AddMimeMapping(".skd", "application/x-koan"); + AddMimeMapping(".skm", "application/x-koan"); + AddMimeMapping(".skp", "application/x-koan"); + AddMimeMapping(".skt", "application/x-koan"); + AddMimeMapping(".sl", "application/x-seelogo"); + AddMimeMapping(".smi", "application/smil"); + AddMimeMapping(".smil", "application/smil"); + AddMimeMapping(".snd", "audio/basic"); + AddMimeMapping(".snd", "audio/x-adpcm"); + AddMimeMapping(".sol", "application/solids"); + AddMimeMapping(".spc", "application/x-pkcs7-certificates"); + AddMimeMapping(".spc", "text/x-speech"); + AddMimeMapping(".spl", "application/futuresplash"); + AddMimeMapping(".spr", "application/x-sprite"); + AddMimeMapping(".sprite", "application/x-sprite"); + AddMimeMapping(".src", "application/x-wais-source"); + AddMimeMapping(".ssi", "text/x-server-parsed-html"); + AddMimeMapping(".ssm", "application/streamingmedia"); + AddMimeMapping(".sst", "application/vnd.ms-pki.certstore"); + AddMimeMapping(".step", "application/step"); + AddMimeMapping(".stl", "application/sla"); + AddMimeMapping(".stl", "application/vnd.ms-pki.stl"); + AddMimeMapping(".stl", "application/x-navistyle"); + AddMimeMapping(".stp", "application/step"); + AddMimeMapping(".sv4cpio", "application/x-sv4cpio"); + AddMimeMapping(".sv4crc", "application/x-sv4crc"); + AddMimeMapping(".svf", "image/vnd.dwg"); + AddMimeMapping(".svf", "image/x-dwg"); + AddMimeMapping(".svr", "application/x-world"); + AddMimeMapping(".svr", "x-world/x-svr"); + AddMimeMapping(".swf", "application/x-shockwave-flash"); + AddMimeMapping(".t", "application/x-troff"); + AddMimeMapping(".talk", "text/x-speech"); + AddMimeMapping(".tar", "application/x-tar"); + AddMimeMapping(".tbk", "application/toolbook"); + AddMimeMapping(".tbk", "application/x-tbook"); + AddMimeMapping(".tcl", "application/x-tcl"); + AddMimeMapping(".tcl", "text/x-script.tcl"); + AddMimeMapping(".tcsh", "text/x-script.tcsh"); + AddMimeMapping(".tex", "application/x-tex"); + AddMimeMapping(".texi", "application/x-texinfo"); + AddMimeMapping(".texinfo", "application/x-texinfo"); + AddMimeMapping(".text", "application/plain"); + AddMimeMapping(".text", "text/plain"); + AddMimeMapping(".tgz", "application/x-compressed"); + AddMimeMapping(".tgz", "application/gnutar"); + AddMimeMapping(".tif", "image/tiff"); + AddMimeMapping(".tif", "image/x-tiff"); + AddMimeMapping(".tiff", "image/tiff"); + AddMimeMapping(".tiff", "image/x-tiff"); + AddMimeMapping(".tr", "application/x-troff"); + AddMimeMapping(".tsi", "audio/tsp-audio"); + AddMimeMapping(".tsp", "application/dsptype"); + AddMimeMapping(".tsp", "audio/tsplayer"); + AddMimeMapping(".tsv", "text/tab-separated-values"); + AddMimeMapping(".turbot", "image/florian"); + AddMimeMapping(".txt", "text/plain"); + AddMimeMapping(".uil", "text/x-uil"); + AddMimeMapping(".uni", "text/uri-list"); + AddMimeMapping(".unis", "text/uri-list"); + AddMimeMapping(".unv", "application/i-deas"); + AddMimeMapping(".uri", "text/uri-list"); + AddMimeMapping(".uris", "text/uri-list"); + AddMimeMapping(".ustar", "application/x-ustar"); + AddMimeMapping(".ustar", "multipart/x-ustar"); + AddMimeMapping(".uu", "application/octet-stream"); + AddMimeMapping(".uu", "text/x-uuencode"); + AddMimeMapping(".uue", "text/x-uuencode"); + AddMimeMapping(".vcd", "application/x-cdlink"); + AddMimeMapping(".vcs", "text/x-vcalendar"); + AddMimeMapping(".vda", "application/vda"); + AddMimeMapping(".vdo", "video/vdo"); + AddMimeMapping(".vew", "application/groupwise"); + AddMimeMapping(".viv", "video/vivo"); + AddMimeMapping(".viv", "video/vnd.vivo"); + AddMimeMapping(".vivo", "video/vivo"); + AddMimeMapping(".vivo", "video/vnd.vivo"); + AddMimeMapping(".vmd", "application/vocaltec-media-desc"); + AddMimeMapping(".vmf", "application/vocaltec-media-file"); + AddMimeMapping(".voc", "audio/voc"); + AddMimeMapping(".voc", "audio/x-voc"); + AddMimeMapping(".vos", "video/vosaic"); + AddMimeMapping(".vox", "audio/voxware"); + AddMimeMapping(".vqe", "audio/x-twinvq-plugin"); + AddMimeMapping(".vqf", "audio/x-twinvq"); + AddMimeMapping(".vql", "audio/x-twinvq-plugin"); + AddMimeMapping(".vrml", "application/x-vrml"); + AddMimeMapping(".vrml", "model/vrml"); + AddMimeMapping(".vrml", "x-world/x-vrml"); + AddMimeMapping(".vrt", "x-world/x-vrt"); + AddMimeMapping(".vsd", "application/x-visio"); + AddMimeMapping(".vst", "application/x-visio"); + AddMimeMapping(".vsw", "application/x-visio"); + AddMimeMapping(".w60", "application/wordperfect6.0"); + AddMimeMapping(".w61", "application/wordperfect6.1"); + AddMimeMapping(".w6w", "application/msword"); + AddMimeMapping(".wav", "audio/wav"); + AddMimeMapping(".wav", "audio/x-wav"); + AddMimeMapping(".wb1", "application/x-qpro"); + AddMimeMapping(".wbmp", "image/vnd.wap.wbmp"); + AddMimeMapping(".web", "application/vnd.xara"); + AddMimeMapping(".wiz", "application/msword"); + AddMimeMapping(".wk1", "application/x-123"); + AddMimeMapping(".wmf", "windows/metafile"); + AddMimeMapping(".wml", "text/vnd.wap.wml"); + AddMimeMapping(".wmlc", "application/vnd.wap.wmlc"); + AddMimeMapping(".wmls", "text/vnd.wap.wmlscript"); + AddMimeMapping(".wmlsc", "application/vnd.wap.wmlscriptc"); + AddMimeMapping(".word", "application/msword"); + AddMimeMapping(".wp", "application/wordperfect"); + AddMimeMapping(".wp5", "application/wordperfect"); + AddMimeMapping(".wp5", "application/wordperfect6.0"); + AddMimeMapping(".wp6", "application/wordperfect"); + AddMimeMapping(".wpd", "application/wordperfect"); + AddMimeMapping(".wpd", "application/x-wpwin"); + AddMimeMapping(".wq1", "application/x-lotus"); + AddMimeMapping(".wri", "application/mswrite"); + AddMimeMapping(".wri", "application/x-wri"); + AddMimeMapping(".wrl", "application/x-world"); + AddMimeMapping(".wrl", "model/vrml"); + AddMimeMapping(".wrl", "x-world/x-vrml"); + AddMimeMapping(".wrz", "model/vrml"); + AddMimeMapping(".wrz", "x-world/x-vrml"); + AddMimeMapping(".wsc", "text/scriplet"); + AddMimeMapping(".wsrc", "application/x-wais-source"); + AddMimeMapping(".wtk", "application/x-wintalk"); + AddMimeMapping(".xbm", "image/x-xbitmap"); + AddMimeMapping(".xbm", "image/x-xbm"); + AddMimeMapping(".xbm", "image/xbm"); + AddMimeMapping(".xdr", "video/x-amt-demorun"); + AddMimeMapping(".xgz", "xgl/drawing"); + AddMimeMapping(".xif", "image/vnd.xiff"); + AddMimeMapping(".xl", "application/excel"); + AddMimeMapping(".xla", "application/excel"); + AddMimeMapping(".xla", "application/x-excel"); + AddMimeMapping(".xla", "application/x-msexcel"); + AddMimeMapping(".xlb", "application/excel"); + AddMimeMapping(".xlb", "application/vnd.ms-excel"); + AddMimeMapping(".xlb", "application/x-excel"); + AddMimeMapping(".xlc", "application/excel"); + AddMimeMapping(".xlc", "application/vnd.ms-excel"); + AddMimeMapping(".xlc", "application/x-excel"); + AddMimeMapping(".xld", "application/excel"); + AddMimeMapping(".xld", "application/x-excel"); + AddMimeMapping(".xlk", "application/excel"); + AddMimeMapping(".xlk", "application/x-excel"); + AddMimeMapping(".xll", "application/excel"); + AddMimeMapping(".xll", "application/vnd.ms-excel"); + AddMimeMapping(".xll", "application/x-excel"); + AddMimeMapping(".xlm", "application/excel"); + AddMimeMapping(".xlm", "application/vnd.ms-excel"); + AddMimeMapping(".xlm", "application/x-excel"); + AddMimeMapping(".xls", "application/vnd.ms-excel"); + AddMimeMapping(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + AddMimeMapping(".xlt", "application/excel"); + AddMimeMapping(".xlt", "application/x-excel"); + AddMimeMapping(".xlv", "application/excel"); + AddMimeMapping(".xlv", "application/x-excel"); + AddMimeMapping(".xlw", "application/excel"); + AddMimeMapping(".xlw", "application/vnd.ms-excel"); + AddMimeMapping(".xlw", "application/x-excel"); + AddMimeMapping(".xlw", "application/x-msexcel"); + AddMimeMapping(".xm", "audio/xm"); + AddMimeMapping(".xml", "application/xml"); + AddMimeMapping(".xml", "text/xml"); + AddMimeMapping(".xmz", "xgl/movie"); + AddMimeMapping(".xpix", "application/x-vnd.ls-xpix"); + AddMimeMapping(".xpm", "image/x-xpixmap"); + AddMimeMapping(".xpm", "image/xpm"); + AddMimeMapping(".x-png", "image/png"); + AddMimeMapping(".xsr", "video/x-amt-showrun"); + AddMimeMapping(".xwd", "image/x-xwd"); + AddMimeMapping(".xwd", "image/x-xwindowdump"); + AddMimeMapping(".xyz", "chemical/x-pdb"); + AddMimeMapping(".z", "application/x-compress"); + AddMimeMapping(".z", "application/x-compressed"); + AddMimeMapping(".zip", "application/zip"); + AddMimeMapping(".zip", "application/x-compressed"); + AddMimeMapping(".zip", "application/x-zip-compressed"); + AddMimeMapping(".zip", "multipart/x-zip"); + AddMimeMapping(".zoo", "application/octet-stream"); + AddMimeMapping(".zsh", "text/x-script.zsh"); + AddMimeMapping(".323", "text/h323"); + AddMimeMapping(".asx", "video/x-ms-asf"); + AddMimeMapping(".acx", "application/internet-property-stream"); + AddMimeMapping(".ai", "application/postscript"); + AddMimeMapping(".aif", "audio/x-aiff"); + AddMimeMapping(".aiff", "audio/aiff"); + AddMimeMapping(".axs", "application/olescript"); + AddMimeMapping(".aifc", "audio/aiff"); + AddMimeMapping(".asr", "video/x-ms-asf"); + AddMimeMapping(".avi", "video/x-msvideo"); + AddMimeMapping(".asf", "video/x-ms-asf"); + AddMimeMapping(".au", "audio/basic"); + AddMimeMapping(".application", "application/x-ms-application"); + AddMimeMapping(".bin", "application/octet-stream"); + AddMimeMapping(".bas", "text/plain"); + AddMimeMapping(".bcpio", "application/x-bcpio"); + AddMimeMapping(".bmp", "image/bmp"); + AddMimeMapping(".cdf", "application/x-cdf"); + AddMimeMapping(".cat", "application/vndms-pkiseccat"); + AddMimeMapping(".crt", "application/x-x509-ca-cert"); + AddMimeMapping(".c", "text/plain"); + AddMimeMapping(".css", "text/css"); + AddMimeMapping(".cer", "application/x-x509-ca-cert"); + AddMimeMapping(".crl", "application/pkix-crl"); + AddMimeMapping(".cmx", "image/x-cmx"); + AddMimeMapping(".csh", "application/x-csh"); + AddMimeMapping(".cod", "image/cis-cod"); + AddMimeMapping(".cpio", "application/x-cpio"); + AddMimeMapping(".clp", "application/x-msclip"); + AddMimeMapping(".crd", "application/x-mscardfile"); + AddMimeMapping(".deploy", "application/octet-stream"); + AddMimeMapping(".dll", "application/x-msdownload"); + AddMimeMapping(".dot", "application/msword"); + AddMimeMapping(".doc", "application/msword"); + AddMimeMapping(".dvi", "application/x-dvi"); + AddMimeMapping(".dir", "application/x-director"); + AddMimeMapping(".dxr", "application/x-director"); + AddMimeMapping(".der", "application/x-x509-ca-cert"); + AddMimeMapping(".dib", "image/bmp"); + AddMimeMapping(".dcr", "application/x-director"); + AddMimeMapping(".disco", "text/xml"); + AddMimeMapping(".exe", "application/octet-stream"); + AddMimeMapping(".etx", "text/x-setext"); + AddMimeMapping(".evy", "application/envoy"); + AddMimeMapping(".eml", "message/rfc822"); + AddMimeMapping(".eps", "application/postscript"); + AddMimeMapping(".flr", "x-world/x-vrml"); + AddMimeMapping(".fif", "application/fractals"); + AddMimeMapping(".gtar", "application/x-gtar"); + AddMimeMapping(".gif", "image/gif"); + AddMimeMapping(".gz", "application/x-gzip"); + AddMimeMapping(".hta", "application/hta"); + AddMimeMapping(".htc", "text/x-component"); + AddMimeMapping(".htt", "text/webviewhtml"); + AddMimeMapping(".h", "text/plain"); + AddMimeMapping(".hdf", "application/x-hdf"); + AddMimeMapping(".hlp", "application/winhlp"); + AddMimeMapping(".html", "text/html"); + AddMimeMapping(".htm", "text/html"); + AddMimeMapping(".hqx", "application/mac-binhex40"); + AddMimeMapping(".isp", "application/x-internet-signup"); + AddMimeMapping(".iii", "application/x-iphone"); + AddMimeMapping(".ief", "image/ief"); + AddMimeMapping(".ivf", "video/x-ivf"); + AddMimeMapping(".ins", "application/x-internet-signup"); + AddMimeMapping(".ico", "image/x-icon"); + AddMimeMapping(".jpg", "image/jpeg"); + AddMimeMapping(".jfif", "image/pjpeg"); + AddMimeMapping(".jpe", "image/jpeg"); + AddMimeMapping(".jpeg", "image/jpeg"); + AddMimeMapping(".png", "image/png"); + AddMimeMapping(".js", "application/x-javascript"); + AddMimeMapping(".lsx", "video/x-la-asf"); + AddMimeMapping(".latex", "application/x-latex"); + AddMimeMapping(".lsf", "video/x-la-asf"); + AddMimeMapping(".manifest", "application/x-ms-manifest"); + AddMimeMapping(".mhtml", "message/rfc822"); + AddMimeMapping(".mny", "application/x-msmoney"); + AddMimeMapping(".mht", "message/rfc822"); + AddMimeMapping(".mid", "audio/mid"); + AddMimeMapping(".mpv2", "video/mpeg"); + AddMimeMapping(".man", "application/x-troff-man"); + AddMimeMapping(".mvb", "application/x-msmediaview"); + AddMimeMapping(".mpeg", "video/mpeg"); + AddMimeMapping(".m3u", "audio/x-mpegurl"); + AddMimeMapping(".mdb", "application/x-msaccess"); + AddMimeMapping(".mpp", "application/vnd.ms-project"); + AddMimeMapping(".m1v", "video/mpeg"); + AddMimeMapping(".mpa", "video/mpeg"); + AddMimeMapping(".me", "application/x-troff-me"); + AddMimeMapping(".m13", "application/x-msmediaview"); + AddMimeMapping(".movie", "video/x-sgi-movie"); + AddMimeMapping(".m14", "application/x-msmediaview"); + AddMimeMapping(".mpe", "video/mpeg"); + AddMimeMapping(".mp2", "video/mpeg"); + AddMimeMapping(".mov", "video/quicktime"); + AddMimeMapping(".mp3", "audio/mpeg"); + AddMimeMapping(".mpg", "video/mpeg"); + AddMimeMapping(".ms", "application/x-troff-ms"); + AddMimeMapping(".nc", "application/x-netcdf"); + AddMimeMapping(".nws", "message/rfc822"); + AddMimeMapping(".oda", "application/oda"); + AddMimeMapping(".ods", "application/oleobject"); + AddMimeMapping(".pmc", "application/x-perfmon"); + AddMimeMapping(".p7r", "application/x-pkcs7-certreqresp"); + AddMimeMapping(".p7b", "application/x-pkcs7-certificates"); + AddMimeMapping(".p7s", "application/pkcs7-signature"); + AddMimeMapping(".pmw", "application/x-perfmon"); + AddMimeMapping(".ps", "application/postscript"); + AddMimeMapping(".p7c", "application/pkcs7-mime"); + AddMimeMapping(".pbm", "image/x-portable-bitmap"); + AddMimeMapping(".ppm", "image/x-portable-pixmap"); + AddMimeMapping(".pub", "application/x-mspublisher"); + AddMimeMapping(".pnm", "image/x-portable-anymap"); + AddMimeMapping(".pml", "application/x-perfmon"); + AddMimeMapping(".p10", "application/pkcs10"); + AddMimeMapping(".pfx", "application/x-pkcs12"); + AddMimeMapping(".p12", "application/x-pkcs12"); + AddMimeMapping(".pdf", "application/pdf"); + AddMimeMapping(".pps", "application/vnd.ms-powerpoint"); + AddMimeMapping(".p7m", "application/pkcs7-mime"); + AddMimeMapping(".pko", "application/vndms-pkipko"); + AddMimeMapping(".pmr", "application/x-perfmon"); + AddMimeMapping(".pma", "application/x-perfmon"); + AddMimeMapping(".pot", "application/vnd.ms-powerpoint"); + AddMimeMapping(".prf", "application/pics-rules"); + AddMimeMapping(".pgm", "image/x-portable-graymap"); + AddMimeMapping(".qt", "video/quicktime"); + AddMimeMapping(".ra", "audio/x-pn-realaudio"); + AddMimeMapping(".rgb", "image/x-rgb"); + AddMimeMapping(".ram", "audio/x-pn-realaudio"); + AddMimeMapping(".rmi", "audio/mid"); + AddMimeMapping(".ras", "image/x-cmu-raster"); + AddMimeMapping(".roff", "application/x-troff"); + AddMimeMapping(".rtf", "application/rtf"); + AddMimeMapping(".rtx", "text/richtext"); + AddMimeMapping(".sv4crc", "application/x-sv4crc"); + AddMimeMapping(".spc", "application/x-pkcs7-certificates"); + AddMimeMapping(".setreg", "application/set-registration-initiation"); + AddMimeMapping(".snd", "audio/basic"); + AddMimeMapping(".stl", "application/vndms-pkistl"); + AddMimeMapping(".setpay", "application/set-payment-initiation"); + AddMimeMapping(".stm", "text/html"); + AddMimeMapping(".shar", "application/x-shar"); + AddMimeMapping(".sh", "application/x-sh"); + AddMimeMapping(".sit", "application/x-stuffit"); + AddMimeMapping(".spl", "application/futuresplash"); + AddMimeMapping(".sct", "text/scriptlet"); + AddMimeMapping(".scd", "application/x-msschedule"); + AddMimeMapping(".sst", "application/vndms-pkicertstore"); + AddMimeMapping(".src", "application/x-wais-source"); + AddMimeMapping(".sv4cpio", "application/x-sv4cpio"); + AddMimeMapping(".tex", "application/x-tex"); + AddMimeMapping(".tgz", "application/x-compressed"); + AddMimeMapping(".t", "application/x-troff"); + AddMimeMapping(".tar", "application/x-tar"); + AddMimeMapping(".tr", "application/x-troff"); + AddMimeMapping(".tif", "image/tiff"); + AddMimeMapping(".txt", "text/plain"); + AddMimeMapping(".texinfo", "application/x-texinfo"); + AddMimeMapping(".trm", "application/x-msterminal"); + AddMimeMapping(".tiff", "image/tiff"); + AddMimeMapping(".tcl", "application/x-tcl"); + AddMimeMapping(".texi", "application/x-texinfo"); + AddMimeMapping(".tsv", "text/tab-separated-values"); + AddMimeMapping(".ustar", "application/x-ustar"); + AddMimeMapping(".uls", "text/iuls"); + AddMimeMapping(".vcf", "text/x-vcard"); + AddMimeMapping(".wps", "application/vnd.ms-works"); + AddMimeMapping(".wav", "audio/wav"); + AddMimeMapping(".wrz", "x-world/x-vrml"); + AddMimeMapping(".wri", "application/x-mswrite"); + AddMimeMapping(".wks", "application/vnd.ms-works"); + AddMimeMapping(".wmf", "application/x-msmetafile"); + AddMimeMapping(".wcm", "application/vnd.ms-works"); + AddMimeMapping(".wrl", "x-world/x-vrml"); + AddMimeMapping(".wdb", "application/vnd.ms-works"); + AddMimeMapping(".wsdl", "text/xml"); + AddMimeMapping(".xml", "text/xml"); + AddMimeMapping(".xlm", "application/vnd.ms-excel"); + AddMimeMapping(".xaf", "x-world/x-vrml"); + AddMimeMapping(".xla", "application/vnd.ms-excel"); + AddMimeMapping(".xof", "x-world/x-vrml"); + AddMimeMapping(".xlt", "application/vnd.ms-excel"); + AddMimeMapping(".xlc", "application/vnd.ms-excel"); + AddMimeMapping(".xsl", "text/xml"); + AddMimeMapping(".xbm", "image/x-xbitmap"); + AddMimeMapping(".xlw", "application/vnd.ms-excel"); + AddMimeMapping(".xpm", "image/x-xpixmap"); + AddMimeMapping(".xwd", "image/x-xwindowdump"); + AddMimeMapping(".xsd", "text/xml"); + AddMimeMapping(".z", "application/x-compress"); + AddMimeMapping(".zip", "application/x-zip-compressed"); + AddMimeSynonym("application/x-zip-compressed", "application/zip"); + AddMimeMapping(".*", "application/octet-stream"); + } + + private static void AddMimeMapping(string extension, string mimeType) + { + if (ExtensionToMimeMappingTable.ContainsKey(extension)) + { + AddMimeSynonym((string)ExtensionToMimeMappingTable[extension], mimeType); + } + else + { + ExtensionToMimeMappingTable.Add(extension, mimeType); + } + } + + private static void AddMimeSynonym(string mime, string synonym) + { + if (!MimeSynonyms.ContainsKey(mime)) + { + MimeSynonyms[mime] = new List(); + } + if (!MimeSynonyms[mime].Contains(synonym)) + { + MimeSynonyms[mime].Add(synonym); + } + } + + public static string GetMimeMapping(string fileName) + { + string str = null; + int startIndex = fileName.LastIndexOf('.'); + if (0 < startIndex && fileName.LastIndexOf('\\') < startIndex) + { + str = (string)ExtensionToMimeMappingTable[fileName.Substring(startIndex)]; + } + if (str == null) + { + str = (string)ExtensionToMimeMappingTable[".*"]; + } + return str; + } + + public static string GetExtention(string mimeMapping) + { + if (string.IsNullOrEmpty(mimeMapping)) return null; + foreach (DictionaryEntry entry in ExtensionToMimeMappingTable) + { + var mime = (string)entry.Value; + if (mime == mimeMapping.ToLowerInvariant()) return (string)entry.Key; + if (MimeSynonyms.ContainsKey(mime)) + { + if (MimeSynonyms[mime].Contains(mimeMapping.ToLowerInvariant())) return (string)entry.Key; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Dav/DavService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Dav/DavService.cs new file mode 100644 index 0000000000..2b011f3b43 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Dav/DavService.cs @@ -0,0 +1,159 @@ +using System; +using System.IO; +using System.Net; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web.Http; +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web.Dav +{ + internal class DavService : HttpService + { + #region Special WebDAV Verb Calls + + private const string xmlPROPFIND = "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + + public WebRequest CreateWebRequestPROPFIND(string url, ICredentials credentials) + { + // build a standard webrequest + var request = CreateWebRequest(url, WebRequestMethodsEx.WebDAV.PropFind, credentials, false, null); + + // build data stream + var contentStream = StreamHelper.ToStream(xmlPROPFIND); + + // write the content into request Stream + using (Stream requestStream = GetRequestStream(request, contentStream.Length)) + { + // copy the data + StreamHelper.CopyStreamData(this, contentStream, requestStream, null, null); + } + + // return the stream + return request; + } + + public WebRequest CreateWebRequestPUT(string url, ICredentials credentials, bool bAllowStreamBuffering) + { + // create the request + var request = CreateWebRequest(url, WebRequestMethodsEx.Http.Put, credentials, bAllowStreamBuffering, null, null) as HttpWebRequest; + + // set the content type + request.ContentType = "application/octet-stream"; + + // go ahead + return request; + } + + public HttpStatusCode PerformMoveWebRequest(string url, string urlNewTarget, ICredentials credentials) + { + // build the service + var svc = new DavService(); + + // set the error code + int code; + WebException e; + + // perform the request + svc.PerformSimpleWebCall(url, WebRequestMethodsEx.WebDAV.Move, credentials, urlNewTarget, out code, out e); + + // return the code + return (HttpStatusCode)code; + } + + public HttpStatusCode PerformCopyWebRequest(string url, string urlNewTarget, ICredentials credentials) + { + // build the service + var svc = new DavService(); + + // set the error code + int code; + WebException e; + + // perform the request + svc.PerformSimpleWebCall(url, WebRequestMethodsEx.WebDAV.Copy, credentials, urlNewTarget, out code, out e); + + // return the code + return (HttpStatusCode)code; + } + + #endregion + + #region Overrides + + public override WebRequest CreateWebRequest(string url, string method, ICredentials credentials, bool bAllowStreamBuffering, object context) + { + // quote the string in the right way + var quotedurl = HttpUtilityEx.GenerateEncodedUriString(new Uri(url)); + + // create base request + WebRequest request = CreateWebRequest(quotedurl, method, credentials, bAllowStreamBuffering, context, DavPreparation) as HttpWebRequest; + + // go ahead + return request; + } + + private static void DavPreparation(WebRequest request, object context) + { + // cast to http webrequest + var hrequest = request as HttpWebRequest; + + // Set default headers + hrequest.Headers["Pragma"] = "no-cache"; + hrequest.Headers["Cache-Control"] = "no-cache"; + hrequest.ContentType = "text/xml"; + hrequest.Accept = "*/*"; + + // for all meta data calls we allow stream buffering in webdav + if (hrequest.Method != WebRequestMethods.Http.Put) + hrequest.AllowWriteStreamBuffering = true; + + // set translate mode + hrequest.Headers["Translate"] = "f"; + + // Retrieve only the requested folder + switch (hrequest.Method) + { + case WebRequestMethodsEx.WebDAV.PropFind: + hrequest.Headers["Depth"] = "1"; + break; + case WebRequestMethodsEx.WebDAV.Move: + { + var targetUri = context as string; + if (targetUri == null) + throw new Exception("Not a valid URL"); + + targetUri = HttpUtilityEx.GenerateEncodedUriString(new Uri(targetUri)); + targetUri = targetUri.Replace(WebDavConfiguration.YaUrl + ":443", WebDavConfiguration.YaUrl); + hrequest.Headers["Destination"] = targetUri; + } + break; + case WebRequestMethodsEx.WebDAV.Copy: + { + var targetUri = context as string; + if (targetUri == null) + throw new Exception("Not a valid URL"); + + targetUri = HttpUtilityEx.GenerateEncodedUriString(new Uri(targetUri)); + targetUri = targetUri.Replace(WebDavConfiguration.YaUrl + ":443", WebDavConfiguration.YaUrl); + hrequest.Headers["Destination"] = targetUri; + hrequest.Headers["Depth"] = "infinity"; + hrequest.Headers["Overwrite"] = "T"; + } + break; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Ftp/FtpService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Ftp/FtpService.cs new file mode 100644 index 0000000000..e690a7f452 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Ftp/FtpService.cs @@ -0,0 +1,136 @@ +using System; +using System.IO; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web.Ftp +{ + internal class FtpService : WebRequestService + { + /// + /// This method creates a directory in the ftp server + /// + /// + /// + /// + public bool FtpCreateDirectory(string uri, ICredentials credentials) + { + return PerformSimpleFtpMethod(uri, WebRequestMethodsEx.Ftp.MakeDirectory, credentials); + } + + /// + /// This method removes a directory + /// + /// + /// + /// + public bool FtpDeleteEmptyDirectory(string uri, ICredentials credentials) + { + return PerformSimpleFtpMethod(uri, WebRequestMethodsEx.Ftp.RemoveDirectory, credentials); + } + + /// + /// This method removes an file + /// + /// + /// + /// + public bool FtpDeleteFile(string uri, ICredentials credentials) + { + return PerformSimpleFtpMethod(uri, WebRequestMethodsEx.Ftp.DeleteFile, credentials); + } + + public bool FtpRename(string uri, string newNameFullPath, ICredentials credentials) + { + // create a webrequest + var renameRequest = (FtpWebRequest)CreateWebRequest(uri, WebRequestMethodsEx.Ftp.Rename, credentials, false, null); + + // set the target + renameRequest.RenameTo = newNameFullPath; + + // perform the operation + try + { + //get response but ignore it + GetStringResponse(renameRequest); + + // ok + return true; + } + catch (Exception) + { + return false; + } + } + + protected override WebRequest CreateBasicWebRequest(Uri uri, bool bAllowStreamBuffering) + { + //create request + var result = (FtpWebRequest)WebRequest.Create(uri); + + //Do not keep alive (stateless mode) + result.KeepAlive = false; + + // go ahead + return result; + } + + /// + /// Obtains a response stream as a string + /// + /// current FTP request + /// String containing response + /// FTP servers typically return strings with CR and + /// not CRLF. Use respons.Replace(vbCR, vbCRLF) to convert + /// to an MSDOS string + private static string GetStringResponse(WebRequest ftp) + { + //Get the result, streaming to a string + string result; + + using (var response = ftp.GetResponse()) + { + using (var datastream = response.GetResponseStream()) + { + using (var sr = new StreamReader(datastream)) + { + result = sr.ReadToEnd(); + sr.Close(); + } + datastream.Close(); + } + response.Close(); + } + + return result; + } + + private bool PerformSimpleFtpMethod(string uri, string requestMethod, ICredentials credentials) + { + // create a webrequest + var simpleFTPRequest = CreateWebRequest(uri, requestMethod, credentials, false, null); + + // perform remove + try + { + //get response but ignore it + GetStringResponse(simpleFTPRequest); + + // ok + return true; + } + catch (Exception) + { + return false; + } + } + + protected override int GetWebResponseStatus(WebResponse response) + { + if (!(response is FtpWebResponse)) + throw new InvalidOperationException("Response is not a FTP reponse"); + + var resp = (FtpWebResponse)response; + return (int)resp.StatusCode; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Http/HttpService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Http/HttpService.cs new file mode 100644 index 0000000000..4223831b06 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/Http/HttpService.cs @@ -0,0 +1,31 @@ +using System; +using System.Net; +using System.Threading; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web.Http +{ + internal class HttpService : WebRequestService + { + protected override WebRequest CreateBasicWebRequest(Uri uri, bool bAllowStreamBuffering) + { + // build the http Webrequest + var request = WebRequest.Create(uri) as HttpWebRequest; + request.AllowAutoRedirect = false; + + request.AllowWriteStreamBuffering = bAllowStreamBuffering; + request.Timeout = Timeout.Infinite; + request.ReadWriteTimeout = Timeout.Infinite; + + // go ahead + return request; + } + + protected override int GetWebResponseStatus(WebResponse response) + { + if (!(response is HttpWebResponse)) + throw new InvalidOperationException("This is not a HTTP based web response"); + + return (int)((response as HttpWebResponse).StatusCode); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutedEventArgs.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutedEventArgs.cs new file mode 100644 index 0000000000..850e26f303 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutedEventArgs.cs @@ -0,0 +1,32 @@ +using System; +using System.IO; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + /// + /// This class contains the argument of the WebRequestExecuted event + /// + public class WebRequestExecutedEventArgs : EventArgs + { + /// + /// The web reponse + /// + public WebResponse response; + + /// + /// The timespan of the webrequest + /// + public TimeSpan timeNeeded; + + /// + /// The result as data stream + /// + public Stream resultStream; + + /// + /// possibe web exception + /// + public WebException exception; + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutingEventArgs.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutingEventArgs.cs new file mode 100644 index 0000000000..dccbd66893 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestExecutingEventArgs.cs @@ -0,0 +1,16 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + /// + /// This class contains the argument of the WebRequestExecuting event + /// + public class WebRequestExecutingEventArgs : EventArgs + { + /// + /// The webrequest which has to be processed as self + /// + public WebRequest request; + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManager.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManager.cs new file mode 100644 index 0000000000..7e2e5f4193 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManager.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + /// + /// This delegate can be used to defines callbacks which will be called after + /// a webrequest is processed + /// + /// the caller of the webrequest + /// The executed evemt args + public delegate void WebRequestExecuted(object sender, WebRequestExecutedEventArgs e); + + /// + /// This delegate can be used to defines callbacks which will be called before + /// a webrequest is processed + /// + /// the caller of the webrequest + /// the executed event args + public delegate void WebRequestExecuting(object sender, WebRequestExecutingEventArgs e); + + /// + /// This class allows to be informed about all oAuth requests in the + /// library. Do not add event receiver during runtime, only during start + /// up of your application + /// + public sealed class WebRequestManager + { + #region Singleton Stuff + + private static readonly WebRequestManager instance = new WebRequestManager(); + + // Explicit static constructor to tell C# compiler + // not to mark type as beforefieldinit + static WebRequestManager() + { + } + + private WebRequestManager() + { + _webProxySettings = null; + } + + /// + /// This is the instance accessor of the oAuthServiceManager + /// + public static WebRequestManager Instance + { + get { return instance; } + } + + #endregion + + private IWebProxy _webProxySettings; + + /// + /// This event will be raised when the webrequest is prepared + /// + public event WebRequestExecuting RequestPreparedEvent; + + /// + /// This event will beraised before a webrequest will be executed + /// + public event WebRequestExecuting RequestExecutingEvent; + + /// + /// This event will be raised after a webrequest was executed + /// + public event WebRequestExecuted RequestExecutedEvent; + + internal void NotifyWebRequestPrepared(WebRequest r) + { + if (RequestPreparedEvent != null) + { + var e = new WebRequestExecutingEventArgs() { request = r }; + RequestPreparedEvent(this, e); + } + } + + internal void NotifyWebRequestExecuting(WebRequest r) + { + if (RequestExecutingEvent != null) + { + var e = new WebRequestExecutingEventArgs() { request = r }; + RequestExecutingEvent(this, e); + } + } + + internal void NotifyWebRequestExecuted(WebResponse response, TimeSpan timeNeeded, Stream resultStream, WebException exception) + { + if (RequestExecutedEvent != null) + { + var e = new WebRequestExecutedEventArgs + { + response = response, + timeNeeded = timeNeeded, + resultStream = resultStream, + exception = exception + }; + + RequestExecutedEvent(this, e); + } + } + + + /// + /// This method allows to set an alternative proxy host. The system wide + /// settings wil be overwritten + /// + /// + /// + /// + public void SetProxySettings(string proxyHost, int proxyPort, ICredentials credentials) + { + if (proxyHost != null) + { + _webProxySettings = new WebProxy(proxyHost, proxyPort); + _webProxySettings.Credentials = credentials; + } + else + _webProxySettings = null; + } + + internal IWebProxy GetProxySettings() + { + return _webProxySettings; + } + + /// + /// This method remove the proxy settings and ensures that no proxy will be used + /// at all + /// + public void SetEmptyProxySettings() + { + _webProxySettings = new WebRequestManagerNullProxy(); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManagerNullProxy.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManagerNullProxy.cs new file mode 100644 index 0000000000..4113d5c1b1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestManagerNullProxy.cs @@ -0,0 +1,24 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal class WebRequestManagerNullProxy : IWebProxy + { + public ICredentials Credentials + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public Uri GetProxy(Uri destination) + { + throw new NotImplementedException(); + } + + public bool IsBypassed(Uri host) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMethods.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMethods.cs new file mode 100644 index 0000000000..87b62cebcc --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMethods.cs @@ -0,0 +1,150 @@ +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal static class WebRequestMethodsEx + { + public static class WebDAV + { + /// + /// MOVE Method. + /// + public const string Move = "MOVE"; + + /// + /// PROPFIND Method. + /// + public const string PropFind = "PROPFIND"; + + /// + /// DELETE Method. + /// + public const string Delete = "DELETE"; + + /// + /// COPY Method. + /// + public const string Copy = "COPY"; + + /// + /// OPTIONS Method. + /// + public const string Options = "OPTIONS"; + } + + // Summary: + // Represents the types of file protocol methods that can be used with a FILE + // request. This class cannot be inherited. + public static class File + { + // Summary: + // Represents the FILE GET protocol method that is used to retrieve a file from + // a specified location. + public const string DownloadFile = "GET"; + // + // Summary: + // Represents the FILE PUT protocol method that is used to copy a file to a + // specified location. + public const string UploadFile = "PUT"; + } + + // Summary: + // Represents the types of FTP protocol methods that can be used with an FTP + // request. This class cannot be inherited. + public static class Ftp + { + // Summary: + // Represents the FTP APPE protocol method that is used to append a file to + // an existing file on an FTP server. + public const string AppendFile = "APPE"; + // + // Summary: + // Represents the FTP DELE protocol method that is used to delete a file on + // an FTP server. + public const string DeleteFile = "DELE"; + // + // Summary: + // Represents the FTP RETR protocol method that is used to download a file from + // an FTP server. + public const string DownloadFile = "RETR"; + public const string GetDateTimestamp = "MDTM"; + // + // Summary: + // Represents the FTP SIZE protocol method that is used to retrieve the size + // of a file on an FTP server. + public const string GetFileSize = "SIZE"; + // + // Summary: + // Represents the FTP NLIST protocol method that gets a short listing of the + // files on an FTP server. + public const string ListDirectory = "NLST"; + // + // Summary: + // Represents the FTP LIST protocol method that gets a detailed listing of the + // files on an FTP server. + public const string ListDirectoryDetails = "LIST"; + // + // Summary: + // Represents the FTP MKD protocol method creates a directory on an FTP server. + public const string MakeDirectory = "MKD"; + // + // Summary: + // Represents the FTP PWD protocol method that prints the name of the current + // working directory. + public const string PrintWorkingDirectory = "PWD"; + // + // Summary: + // Represents the FTP RMD protocol method that removes a directory. + public const string RemoveDirectory = "RMD"; + // + // Summary: + // Represents the FTP RENAME protocol method that renames a directory. + public const string Rename = "RENAME"; + // + // Summary: + // Represents the FTP STOR protocol method that uploads a file to an FTP server. + public const string UploadFile = "STOR"; + // + // Summary: + // Represents the FTP STOU protocol that uploads a file with a unique name to + // an FTP server. + public const string UploadFileWithUniqueName = "STOU"; + } + + // Summary: + // Represents the types of HTTP protocol methods that can be used with an HTTP + // request. + public static class Http + { + // Summary: + // Represents the HTTP CONNECT protocol method that is used with a proxy that + // can dynamically switch to tunneling, as in the case of SSL tunneling. + public const string Connect = "CONNECT"; + // + // Summary: + // Represents an HTTP GET protocol method. + public const string Get = "GET"; + // + // Summary: + // Represents an HTTP HEAD protocol method. The HEAD method is identical to + // GET except that the server only returns message-headers in the response, + // without a message-body. + public const string Head = "HEAD"; + // + // Summary: + // Represents an HTTP MKCOL request that creates a new collection (such as a + // collection of pages) at the location specified by the request-Uniform Resource + // Identifier (URI). + public const string MkCol = "MKCOL"; + // + // Summary: + // Represents an HTTP POST protocol method that is used to post a new entity + // as an addition to a URI. + public const string Post = "POST"; + // + // Summary: + // Represents an HTTP PUT protocol method that is used to replace an entity + // identified by a URI. + public const string Put = "PUT"; + } + + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMultipartFormDataSupport.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMultipartFormDataSupport.cs new file mode 100644 index 0000000000..02ba47af94 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestMultipartFormDataSupport.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Net; +using System.Text; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal class WebRequestMultipartFormDataSupport + { + private const string FormBoundary = "-----------------------------28947758029299"; + + public string GetMultipartFormContentType() + { + return string.Format("multipart/form-data; boundary={0}", FormBoundary); + } + + public long GetHeaderFooterSize(string fileName) + { + var header = GetHeaderData(fileName); + var footer = GetFooterString(); + + return header.Length + footer.Length; + } + + /// + /// This method prepares a webrequest to be a multpart data requets + /// + /// + public void PrepareWebRequest(WebRequest request) + { + request.Method = "POST"; + request.ContentType = GetMultipartFormContentType(); + } + + /// + /// This method opens a network file data stream which means the http(s) + /// will be established to the server + /// + /// + /// + /// + public void PrepareRequestStream(Stream requestStream, string fileName) + { + // Add just the first part of this param, since we will write the file data directly to the Stream + var header = GetHeaderData(fileName); + + // write the header into stream + requestStream.Write(header, 0, header.Length); + } + + /// + /// This method writes the footer into the data stream + /// + /// + public void FinalizeNetworkFileDataStream(Stream networkStream) + { + var encoding = Encoding.UTF8; + var footer = GetFooterString(); + networkStream.Write(encoding.GetBytes(footer), 0, footer.Length); + } + + /// + /// Check if the current request us a multipart upload file + /// + /// + /// + public bool IsRequestMultiPartUpload(WebRequest request) + { + try + { + if (request.ContentType == null) + return false; + if (request.ContentType.Equals(GetMultipartFormContentType())) + return true; + return false; + } + catch (NotSupportedException) + { + return false; + } + } + + private static byte[] GetHeaderData(string fileName) + { + var utf8 = new UTF8Encoding(); + var data = utf8.GetBytes(string.Format("--{0}{4}Content-Disposition: form-data; name=\"{2}\"; filename=\"{1}\";{4}Content-Type: {3}{4}{4}", + FormBoundary, + fileName, + "file", + "application/octet-stream", + Environment.NewLine)); + return data; + } + + private static string GetFooterString() + { + return string.Format("{1}--{0}--{1}", FormBoundary, Environment.NewLine); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestService.cs new file mode 100644 index 0000000000..6dcc8a1a3a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestService.cs @@ -0,0 +1,521 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Text.RegularExpressions; +using System.Threading; +using AppLimit.CloudComputing.SharpBox.Common.IO; + + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal abstract class WebRequestService + { + private const string watchTag = "WebRequestServiceRequestWatch"; + + #region StopWatch Helper + + private static void StopStopWatch(WebResponse response, Stream ret, WebException exception) + { + // 2. stop the watch from tls + var slot = Thread.GetNamedDataSlot(watchTag); + var watch = Thread.GetData(slot) as Stopwatch; + + if (watch != null) + { + // stop watch + watch.Stop(); + + // notify + WebRequestManager.Instance.NotifyWebRequestExecuted(response, watch.Elapsed, ret, exception); + } + } + + #endregion + + #region Base Web Methods + + /// + /// This method generates a new webrequest and instruments the stopwatch + /// counter + /// + /// + /// + /// + /// + /// + /// + public virtual WebRequest CreateWebRequest(string url, string method, ICredentials credentials, bool bAllowStreamBuffering, object context) + { + return CreateWebRequest(url, method, credentials, bAllowStreamBuffering, context, null); + } + + /// + /// The callback + /// + /// + /// + public delegate void CreateWebRequestPreparationCallback(WebRequest request, object context); + + /// + /// Internal web request generator + /// + /// + /// + /// + /// + /// + /// + /// + protected WebRequest CreateWebRequest(string url, string method, ICredentials credentials, bool bAllowStreamBuffering, object context, CreateWebRequestPreparationCallback callback) + { + // 1. create and start the watch + var watch = new Stopwatch(); + watch.Start(); + + // 2. build uri + var uriNew = new Uri(url); + + // 2. create request + var request = CreateBasicWebRequest(uriNew, bAllowStreamBuffering); + request.Method = method.ToUpper(); + + // 3. call back + if (callback != null) + callback(request, context); + + // 4. set the proxy class if needed + if (WebRequestManager.Instance.GetProxySettings() != null) + request.Proxy = WebRequestManager.Instance.GetProxySettings(); + + // 4.1. check if we got a null proxy + if (request.Proxy is WebRequestManagerNullProxy) + request.Proxy = null; + + // 5. set the credentials if needed + if (credentials != null) + { + request.Credentials = credentials; + + try + { + request.PreAuthenticate = true; + } + catch (NotSupportedException) + { + } + } + + // 6. notify + WebRequestManager.Instance.NotifyWebRequestPrepared(request); + + // 7. add watch object to tls + var slot = Thread.GetNamedDataSlot(watchTag); + Thread.SetData(slot, watch); + + // 8. return the request + return request; + } + + /// + /// Please implement this method for the right WebRequest type + /// + /// + /// + /// + protected abstract WebRequest CreateBasicWebRequest(Uri uri, bool bAllowStreamBuffering); + + /// + /// This method returns a webrequest data stream and should be used in + /// a using clause + /// + /// + /// + /// + public virtual WebRequestStream GetRequestStream(WebRequest request, long length) + { + // set the conten length + request.ContentLength = length; + + // get the network stream + var nwStream = WebRequestStreamHelper.GetRequestStream(request); + + // return the request streaM; + var ws = new WebRequestStream(nwStream, request, this); + + // add pre dispose opp + ws.PushPreDisposeOperation(DisposeWebRequestStreams, request, ws); + + // go ahead + return ws; + } + + /// + /// This method contains the routine which has to be executed when a request + /// stream will be disposed and will be called autoamtically + /// + private static void DisposeWebRequestStreams(params object[] arg) + { + // get the params + var request = arg[0] as WebRequest; + var stream = arg[1] as WebRequestStream; + + // check if we have a multipart upload + var md = new WebRequestMultipartFormDataSupport(); + if (md.IsRequestMultiPartUpload(request)) + md.FinalizeNetworkFileDataStream(stream); + } + + /// + /// This method returns a webresponse or throws an exception. In the case of an + /// exception the stop watch is stop here + /// + /// + /// + public virtual WebResponse GetWebResponse(WebRequest request) + { + // execute the webrequest + try + { + // check the length + if (request.ContentLength == -1) + { + request.ContentLength = 0; + request.ContentType = ""; + } + + // Notify + WebRequestManager.Instance.NotifyWebRequestExecuting(request); + + // get the response + return WebRequestStreamHelper.GetResponse(request); + } + catch (WebException e) + { + // stop the watch + StopStopWatch(null, null, e); + + // rethrow the exception + throw; + } + } + + /// + /// This method returns an response stream + /// + /// + /// + public virtual Stream GetResponseStream(WebResponse response) + { + Stream responseStream = null; + + try + { + // get the network stream + var nwStream = WebRequestStreamHelper.GetResponseStream(response); + + // get the response stream + responseStream = new WebResponseStream(nwStream, response, this); + } + catch (WebException) + { + return null; + } + finally + { + StopStopWatch(response, responseStream, null); + } + + // return the stream + return responseStream; + } + + /// + /// This method executes alle dispose code for webresponse streams + /// + /// + /// + public virtual void DisposeWebResponseStreams(WebResponse response, WebResponseStream stream) + { + } + + /// + /// Please override this method to ensure that the system can evaluate the + /// protocol specific error code + /// + /// + /// + protected abstract int GetWebResponseStatus(WebResponse response); + + #endregion + + #region Comfort Functions + + /// + /// Performs a five webrequest and returns the result as an in memory stream + /// + /// + /// + /// + public MemoryStream PerformWebRequest(WebRequest request, object context) + { + int code; + WebException e; + return PerformWebRequest(request, context, out code, out e); + } + + /// + /// Performs a five webrequest and returns the result as an in memory stream + /// + /// + /// + /// + /// + /// + public MemoryStream PerformWebRequest(WebRequest request, object context, out int protocolSpecificStatusCode, out WebException errorInfo) + { + return PerformWebRequest(request, context, out protocolSpecificStatusCode, out errorInfo, null); + } + + /// + /// Performs a five webrequest and returns the result as an in memory stream + /// + /// + /// + /// + /// + /// + /// + public MemoryStream PerformWebRequest(WebRequest request, object context, out int protocolSpecificStatusCode, out WebException errorInfo, Func httpCodeCondition) + { + WebHeaderCollection headers; + return PerformWebRequest(request, context, null, out protocolSpecificStatusCode, out errorInfo, out headers, httpCodeCondition); + } + + /// + /// Performs a five webrequest and returns the result as an in memory stream + /// + /// + /// + /// + /// + /// + /// + /// + public MemoryStream PerformWebRequest(WebRequest request, object context, Stream content, out int protocolSpecificStatusCode, out WebException errorInfo, out WebHeaderCollection headers) + { + return PerformWebRequest(request, context, content, out protocolSpecificStatusCode, out errorInfo, out headers, null); + } + + /// + /// Performs a five webrequest and returns the result as an in memory stream + /// + /// + /// + /// + /// + /// + /// + /// + /// + public MemoryStream PerformWebRequest(WebRequest request, object context, Stream content, out int protocolSpecificStatusCode, out WebException errorInfo, out WebHeaderCollection headers, Func httpCodeCondition) + { + // no error + errorInfo = null; + headers = null; + + // start + try + { + // add content if needed + if (content != null) + { + using (Stream requestStream = GetRequestStream(request, content.Length)) + { + StreamHelper.CopyStreamData(this, content, requestStream, null, null); + } + } + + // create the memstream + var memStream = new MemoryStream(); + + // get the response + using (var response = GetWebResponse(request)) + { + + // set the error code + protocolSpecificStatusCode = GetWebResponseStatus(response); + + // handle move + if (protocolSpecificStatusCode == (int)HttpStatusCode.Moved) + { + // set the headers + headers = response.Headers; + } + else if (httpCodeCondition != null && httpCodeCondition(protocolSpecificStatusCode)) + { + //Just return. Do nothing + } + else + { + // read the data + using (var responseStream = GetResponseStream(response)) + { + // copy the data into memory + StreamHelper.CopyStreamData(this, responseStream, memStream, null, null); + + // reset the memory stream + memStream.Position = 0; + + // close the source stream + responseStream.Close(); + } + } + + // close the response + response.Close(); + } + + // return the byte stream + return memStream; + } + catch (WebException e) + { + if (e.Response == null) + protocolSpecificStatusCode = (int)HttpStatusCode.BadRequest; + else + protocolSpecificStatusCode = GetWebResponseStatus(e.Response); + + errorInfo = e; + return null; + } + } + + /// + /// Forms a webrequest and performs them. The result will generated as memory stream + /// + /// + /// + /// + /// + /// + public MemoryStream PerformSimpleWebCall(string url, string method, ICredentials credentials, object context) + { + int code; + WebException e; + return PerformSimpleWebCall(url, method, credentials, context, out code, out e); + } + + /// + /// Forms a webrequest and performs them. The result will generated as memory stream + /// + /// + /// + /// + /// + /// + /// + /// + public MemoryStream PerformSimpleWebCall(string url, string method, ICredentials credentials, object context, out int code, out WebException errorInfo) + { + return PerformSimpleWebCall(url, method, credentials, null, context, out code, out errorInfo); + } + + /// + /// Forms a webrequest and performs them. The result will generated as memory stream + /// + /// + /// + /// + /// + /// + /// + /// + /// + public MemoryStream PerformSimpleWebCall(string url, string method, ICredentials credentials, Stream content, object context, out int code, out WebException errorInfo) + { + // create a web request + var request = CreateWebRequest(url, method, credentials, false, context); + if (request == null) + throw new Exception("Could not generate WebRequest for " + method + ":" + url); + + WebHeaderCollection headers; + var s = PerformWebRequest(request, context, content, out code, out errorInfo, out headers); + + if (code == (int)HttpStatusCode.Moved && request is HttpWebRequest) + { + // get new location + var newLoc = headers["Location"]; + + // do it again + return PerformSimpleWebCall(newLoc, method, credentials, content, context, out code, out errorInfo); + } + + NetworkCredential networkCredential; + if (code == (int)HttpStatusCode.Unauthorized && request is HttpWebRequest && (networkCredential = credentials as NetworkCredential) != null) + { + var search = new Regex(@"^\w+", RegexOptions.Singleline | RegexOptions.IgnoreCase); + // get authentication method + var authMethod = search.Match(errorInfo.Response.Headers["WWW-Authenticate"]).Value; + var newCredentials = new CredentialCache { { new Uri((new Uri(url)).GetLeftPart(UriPartial.Authority)), authMethod, networkCredential } }; + + // do it again + return PerformSimpleWebCall(url, method, newCredentials, content, context, out code, out errorInfo); + } + + // go ahead + return s; + } + + #endregion + + #region Multi Part Form Data Support + + /// + /// This method implements a standard multipart/form-data upload and can be overriden + /// e.g. for WebDav upload + /// + /// + /// + /// + public virtual WebRequest CreateWebRequestMultiPartUpload(string url, ICredentials credentials) + { + // 1. build a valid webrequest + var request = CreateWebRequest(url, WebRequestMethodsEx.Http.Post, credentials, false, null); + + // 2. set the request paramter + var mp = new WebRequestMultipartFormDataSupport(); + mp.PrepareWebRequest(request); + + // 3. go ahead + return request; + } + + public virtual WebRequestStream GetRequestStreamMultiPartUpload(WebRequest request, string fileName, long fileSize) + { + // generate mp support + var mp = new WebRequestMultipartFormDataSupport(); + + // set the right size + fileSize = fileSize + mp.GetHeaderFooterSize(fileName); + + // set the streaming buffering + if (fileSize > 0) + { + // set the maximum content length size + request.ContentLength = fileSize; + } + + // get the stream + var stream = GetRequestStream(request, fileSize); + + // prepare the stream + mp.PrepareRequestStream(stream, fileName); + + // go ahead + return stream; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStream.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStream.cs new file mode 100644 index 0000000000..25d7fed1e6 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStream.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal delegate void WebRequestStreamDisposeOperation(params object[] args); + + internal class WebRequestStream : Stream, IDisposable + { + private Stream _requestStream; + private Stack _PostDisposeOperations; + private Stack _PreDisposeOperations; + private Dictionary _DisposeOperationsParams; + + public long WrittenBytes { get; set; } + + public WebRequestStream(Stream srcStream, WebRequest request, WebRequestService service) + { + _requestStream = srcStream; + _PostDisposeOperations = new Stack(); + _PreDisposeOperations = new Stack(); + _DisposeOperationsParams = new Dictionary(); + + WrittenBytes = 0; + } + + public void PushPostDisposeOperation(WebRequestStreamDisposeOperation opp, params object[] args) + { + _PostDisposeOperations.Push(opp); + + if (args != null) + _DisposeOperationsParams.Add(opp, args); + } + + public void PushPreDisposeOperation(WebRequestStreamDisposeOperation opp, params object[] args) + { + _PreDisposeOperations.Push(opp); + + if (args != null) + _DisposeOperationsParams.Add(opp, args); + } + + public override bool CanRead + { + get { return _requestStream.CanRead; } + } + + public override bool CanSeek + { + get { return _requestStream.CanSeek; } + } + + public override bool CanWrite + { + get { return _requestStream.CanWrite; } + } + + public override void Flush() + { + _requestStream.Flush(); + } + + public override long Length + { + get { return _requestStream.Length; } + } + + public override long Position + { + get { return _requestStream.Position; } + set { _requestStream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _requestStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _requestStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _requestStream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + WrittenBytes += count; + + _requestStream.Write(buffer, offset, count); + } + + #region IDisposable Members + + void IDisposable.Dispose() + { + // dispose our pre opps + PerformeDisposeOperations(_PreDisposeOperations); + + // to all dispose stuff from base + Dispose(); + + // dispose our post opps + PerformeDisposeOperations(_PostDisposeOperations); + } + + private void PerformeDisposeOperations(Stack stack) + { + // dispose our opps + while (stack.Count > 0) + { + // pop the opp + var dop = stack.Pop(); + + // get the args + object[] args; + _DisposeOperationsParams.TryGetValue(dop, out args); + + // perform opp + dop(args); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStreamHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStreamHelper.cs new file mode 100644 index 0000000000..e8e86a975b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebRequestStreamHelper.cs @@ -0,0 +1,24 @@ +using System.IO; +using System.Net; + + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal class WebRequestStreamHelper + { + public static Stream GetRequestStream(WebRequest request) + { + return request.GetRequestStream(); + } + + public static WebResponse GetResponse(WebRequest request) + { + return request.GetResponse(); + } + + public static Stream GetResponseStream(WebResponse response) + { + return response.GetResponseStream(); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebResponseStream.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebResponseStream.cs new file mode 100644 index 0000000000..8a41f1b5f9 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/Web/WebResponseStream.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.Web +{ + internal class WebResponseStream : Stream, IDisposable + { + private Stream _responseStream; + private WebResponse _response; + private WebRequestService _service; + + public WebResponseStream(Stream srcStream, WebResponse response, WebRequestService service) + { + _responseStream = srcStream; + _response = response; + _service = service; + } + + public override bool CanRead + { + get { return _responseStream.CanRead; } + } + + public override bool CanSeek + { + get { return _responseStream.CanSeek; } + } + + public override bool CanWrite + { + get { return _responseStream.CanWrite; } + } + + public override void Flush() + { + _responseStream.Flush(); + } + + public override long Length + { + get { return _responseStream.Length; } + } + + public override long Position + { + get { return _responseStream.Position; } + set { _responseStream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _responseStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _responseStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _responseStream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _responseStream.Write(buffer, offset, count); + } + + #region IDisposable Members + + void IDisposable.Dispose() + { + // dispose our request + _service.DisposeWebResponseStreams(_response, this); + + // to all dispose stuff from base + Dispose(); + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthConsumerContext.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthConsumerContext.cs new file mode 100644 index 0000000000..f5ea051a68 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthConsumerContext.cs @@ -0,0 +1,19 @@ +using System; + +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context +{ + internal class OAuthConsumerContext + { + public readonly string ConsumerKey; + public readonly string ConsumerSecret; + public readonly SignatureTypes SignatureMethod = SignatureTypes.HMACSHA1; + + public OAuthConsumerContext(string consumerKey, string consumerSecret) + { + ConsumerKey = consumerKey; + ConsumerSecret = consumerSecret; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthServiceContext.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthServiceContext.cs new file mode 100644 index 0000000000..a6cf6f35e8 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Context/OAuthServiceContext.cs @@ -0,0 +1,20 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context +{ + internal class OAuthServiceContext + { + public readonly string RequestTokenUrl; + public readonly string AuthorizationUrl; + public readonly string CallbackUrl; + public readonly string AccessTokenUrl; + + public OAuthServiceContext(string requestTokenUrl, string authorizationUrl, string callbackUrl, string accessTokenUrl) + { + RequestTokenUrl = requestTokenUrl; + AuthorizationUrl = authorizationUrl; + CallbackUrl = callbackUrl; + AccessTokenUrl = accessTokenUrl; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthBase.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthBase.cs new file mode 100644 index 0000000000..9a3e04f378 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthBase.cs @@ -0,0 +1,369 @@ +using System; +using System.Security.Cryptography; +using System.Collections.Generic; +using System.Text; +using System.Globalization; + + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl +{ + /// + /// Provides a predefined set of algorithms that are supported officially by the protocol + /// + internal enum SignatureTypes + { + HMACSHA1, + PLAINTEXT, + RSASHA1 + } + + internal class OAuthBase + { + /// + /// Provides an internal structure to sort the query parameter + /// + protected class QueryParameter + { + private readonly string _name; + private readonly string _value; + + public QueryParameter(string name, string value) + { + _name = name; + _value = value; + } + + public string Name + { + get { return _name; } + } + + public string Value + { + get { return _value; } + } + } + + /// + /// Comparer class used to perform the sorting of the query parameters + /// + protected class QueryParameterComparer : IComparer + { + + #region IComparer Members + + public int Compare(QueryParameter x, QueryParameter y) + { + if (x.Name == y.Name) + { + return string.Compare(x.Value, y.Value); + } + return string.Compare(x.Name, y.Name); + } + + #endregion + } + + protected const string OAuthVersion = "1.0"; + protected const string OAuthParameterPrefix = "oauth_"; + + // + // List of know and used oauth parameters' names + // + protected const string OAuthConsumerKeyKey = "oauth_consumer_key"; + protected const string OAuthCallbackKey = "oauth_callback"; + protected const string OAuthVersionKey = "oauth_version"; + protected const string OAuthSignatureMethodKey = "oauth_signature_method"; + protected const string OAuthSignatureKey = "oauth_signature"; + protected const string OAuthTimestampKey = "oauth_timestamp"; + protected const string OAuthNonceKey = "oauth_nonce"; + protected const string OAuthTokenKey = "oauth_token"; + protected const string OAuthTokenSecretKey = "oauth_token_secret"; + + protected const string HMACSHA1SignatureType = "HMAC-SHA1"; + protected const string PlainTextSignatureType = "PLAINTEXT"; + protected const string RSASHA1SignatureType = "RSA-SHA1"; + + protected Random random = new Random(); + + private static readonly char[] OAuthIgnoreChars = new[] { '_', '-', '.', '~' }; + + /// + /// Helper function to compute a hash value + /// + /// The hashing algoirhtm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function + /// The data to hash + /// a Base64 string of the hash value + private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) + { + if (hashAlgorithm == null) + { + throw new ArgumentNullException("hashAlgorithm"); + } + + if (string.IsNullOrEmpty(data)) + { + throw new ArgumentNullException("data"); + } + + var dataBuffer = Encoding.UTF8.GetBytes(data); + var hashBytes = hashAlgorithm.ComputeHash(dataBuffer); + + return Convert.ToBase64String(hashBytes); + } + + /// + /// Internal function to cut out all non oauth query string parameters (all parameters not begining with "oauth_") + /// + /// The query string part of the Url + /// A list of QueryParameter each containing the parameter name and value + private static List GetQueryParameters(string parameters) + { + if (parameters.StartsWith("?")) + { + parameters = parameters.Remove(0, 1); + } + + var result = new List(); + + if (!string.IsNullOrEmpty(parameters)) + { + var p = parameters.Split('&'); + foreach (var s in p) + { + if (!string.IsNullOrEmpty(s) /*&& !s.StartsWith(OAuthParameterPrefix)*/) + { + if (s.IndexOf('=') > -1) + { + var temp = s.Split('='); + result.Add(new QueryParameter(temp[0], temp[1])); + } + else + { + result.Add(new QueryParameter(s, string.Empty)); + } + } + } + } + + return result; + } + + /// + /// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case. + /// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth + /// + /// The value to Url encode + /// Returns a Url encoded string + public static string UrlEncode(string value) + { + return UrlEncode(value, OAuthIgnoreChars); + } + + public static string UrlEncode(string value, params char[] ignoreChars) + { + if (string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + var sb = new StringBuilder(); + foreach (var ch in value) + { + if (char.IsLetterOrDigit(ch) || Array.Exists(ignoreChars, x => x == ch)) + sb.Append(ch); + else + { + var bytes = Encoding.UTF8.GetBytes(ch.ToString()); + foreach (var b in bytes) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "%{0:X2}", b); + } + } + } + + return sb.ToString(); + } + + /// + /// Normalizes the request parameters according to the spec + /// + /// The list of parameters already sorted + /// a string representing the normalized parameters + protected string NormalizeRequestParameters(IList parameters) + { + var sb = new StringBuilder(); + for (var i = 0; i < parameters.Count; i++) + { + var p = parameters[i]; + sb.AppendFormat("{0}={1}", p.Name, p.Value); + + if (i < parameters.Count - 1) + { + sb.Append("&"); + } + } + + return sb.ToString(); + } + + /// + /// Generate the signature base that is used to produce the signature + /// + /// The full url that needs to be signed including its non OAuth url parameters + /// The consumer key + /// The token, if available. If not available pass null or an empty string + /// The token secret, if available. If not available pass null or an empty string + /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc) + /// The timestamp which is used in the signature baser + /// A unique value with identifies the request, this value can't be used more then one times + /// The signature type. To use the default values use OAuthBase.SignatureTypes. + /// The URL without parameters + /// The request parameters + /// The signature base + public string GenerateSignatureBase(Uri url, string consumerKey, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, string signatureType, out string normalizedUrl, out string normalizedRequestParameters) + { + if (token == null) + { + token = string.Empty; + } + + if (string.IsNullOrEmpty(consumerKey)) + { + throw new ArgumentNullException("consumerKey"); + } + + if (string.IsNullOrEmpty(httpMethod)) + { + throw new ArgumentNullException("httpMethod"); + } + + if (string.IsNullOrEmpty(signatureType)) + { + throw new ArgumentNullException("signatureType"); + } + + var parameters = GetQueryParameters(url.Query.Replace("!", "%21")); + parameters.Add(new QueryParameter(OAuthVersionKey, OAuthVersion)); + parameters.Add(new QueryParameter(OAuthNonceKey, nonce)); + parameters.Add(new QueryParameter(OAuthTimestampKey, timeStamp)); + parameters.Add(new QueryParameter(OAuthSignatureMethodKey, signatureType)); + parameters.Add(new QueryParameter(OAuthConsumerKeyKey, consumerKey)); + + if (!string.IsNullOrEmpty(token)) + { + parameters.Add(new QueryParameter(OAuthTokenKey, token)); + } + + parameters.Sort(new QueryParameterComparer()); + + normalizedUrl = string.Format("{0}://{1}", url.Scheme, url.Host); + if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) + { + normalizedUrl += ":" + url.Port; + } + normalizedUrl += url.AbsolutePath.Replace("'", "%27").Replace("!", "%21"); + normalizedRequestParameters = NormalizeRequestParameters(parameters); + + var signatureBase = new StringBuilder(); + signatureBase.AppendFormat("{0}&", httpMethod.ToUpper()); + signatureBase.AppendFormat("{0}&", UrlEncode(normalizedUrl)); + signatureBase.AppendFormat("{0}", UrlEncode(normalizedRequestParameters)); + + return signatureBase.ToString(); + } + + /// + /// Generate the signature value based on the given signature base and hash algorithm + /// + /// The signature based as produced by the GenerateSignatureBase method or by any other means + /// The hash algorithm used to perform the hashing. If the hashing algorithm requires initialization or a key it should be set prior to calling this method + /// A base64 string of the hash value + public string GenerateSignatureUsingHash(string signatureBase, HashAlgorithm hash) + { + return ComputeHash(hash, signatureBase); + } + + /// + /// Generates a signature using the HMAC-SHA1 algorithm + /// + /// The full url that needs to be signed including its non OAuth url parameters + /// The consumer key + /// The consumer seceret + /// The token, if available. If not available pass null or an empty string + /// The token secret, if available. If not available pass null or an empty string + /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc) + /// The timestamp which is used in the signature baser + /// A unique value with identifies the request, this value can't be used more then one times + /// The URL without parameters + /// The request parameters + /// A base64 string of the hash value + public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, out string normalizedUrl, out string normalizedRequestParameters) + { + return GenerateSignature(url, consumerKey, consumerSecret, token, tokenSecret, httpMethod, timeStamp, nonce, SignatureTypes.HMACSHA1, out normalizedUrl, out normalizedRequestParameters); + } + + /// + /// Generates a signature using the specified signatureType + /// + /// The full url that needs to be signed including its non OAuth url parameters + /// The consumer key + /// The consumer seceret + /// The token, if available. If not available pass null or an empty string + /// The token secret, if available. If not available pass null or an empty string + /// The http method used. Must be a valid HTTP method verb (POST,GET,PUT, etc) + /// The timestamp which is used in the signature baser + /// A unique value with identifies the request, this value can't be used more then one times + /// The signature type. To use the default values use OAuthBase.SignatureTypes. + /// The URL without parameters + /// The request parameters + /// A base64 string of the hash value + public string GenerateSignature(Uri url, string consumerKey, string consumerSecret, string token, string tokenSecret, string httpMethod, string timeStamp, string nonce, SignatureTypes signatureType, out string normalizedUrl, out string normalizedRequestParameters) + { + normalizedUrl = null; + normalizedRequestParameters = null; + + switch (signatureType) + { + case SignatureTypes.PLAINTEXT: + return string.Format("{0}&{1}", consumerSecret, tokenSecret); + case SignatureTypes.HMACSHA1: + string signatureBase = GenerateSignatureBase(url, consumerKey, token, tokenSecret, httpMethod, timeStamp, nonce, HMACSHA1SignatureType, out normalizedUrl, out normalizedRequestParameters); + + using (var hmacsha1 = new HMACSHA1()) + { + hmacsha1.Key = Encoding.UTF8.GetBytes(string.Format("{0}&{1}", UrlEncode(consumerSecret), string.IsNullOrEmpty(tokenSecret) ? "" : UrlEncode(tokenSecret))); + + return GenerateSignatureUsingHash(signatureBase, hmacsha1); + } + case SignatureTypes.RSASHA1: + throw new NotImplementedException(); + default: + throw new ArgumentException("Unknown signature type", "signatureType"); + } + } + + /// + /// Generate the timestamp for the signature + /// + /// + public virtual string GenerateTimeStamp() + { + // Default implementation of UNIX time of the current UTC time + var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); + return Convert.ToInt64(ts.TotalSeconds).ToString(); + } + + /// + /// Generate a nonce + /// + /// + public virtual string GenerateNonce() + { + // a nonce is a random string so we will try uuid + var nonce = Guid.NewGuid().ToString("N"); + // go ahead + return nonce; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthStreamParser.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthStreamParser.cs new file mode 100644 index 0000000000..cfda834a06 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthStreamParser.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl +{ + internal class OAuthStreamParser + { + public static OAuthToken ParseTokenInformation(Stream data) + { + var parameters = ParseParameterResult(data); + return new OAuthToken(parameters["oauth_token"], parameters["oauth_token_secret"]); + } + + private static Dictionary ParseParameterResult(Stream data) + { + var result = GetResultString(data); + + if (result.Length > 0) + { + var parameters = result.Split('&'); + + return parameters.Select(paramSet => paramSet.Split('=')).ToDictionary(param2 => param2[0], param2 => param2[1]); + } + + return null; + } + + + private static string GetResultString(Stream data) + { + using (var reader = new StreamReader(data)) + { + return reader.ReadToEnd(); + } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthUrlGenerator.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthUrlGenerator.cs new file mode 100644 index 0000000000..1141750aa6 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Impl/OAuthUrlGenerator.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; + + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl +{ + internal class OAuthUrlGenerator + { + public static string GenerateRequestTokenUrl(string baseRequestTokenUrl, OAuthConsumerContext context) + { + return GenerateSignedUrl(baseRequestTokenUrl, WebRequestMethodsEx.Http.Get, context, null); + } + + public static string GenerateAuthorizationUrl(string baseAuthorizeUrl, string callbackUrl, OAuthToken requestToken) + { + var sb = new StringBuilder(baseAuthorizeUrl); + + sb.AppendFormat("?oauth_token={0}", requestToken.TokenKey); + sb.AppendFormat("&oauth_callback={0}", OAuthBase.UrlEncode(callbackUrl, '.')); + + return sb.ToString(); + } + + public static string GenerateAccessTokenUrl(string baseAccessTokenUrl, OAuthConsumerContext context, OAuthToken requestToken) + { + return GenerateSignedUrl(baseAccessTokenUrl, WebRequestMethodsEx.Http.Get, context, requestToken); + } + + private static string GenerateSignedUrl(string baseRequestTokenUrl, string method, OAuthConsumerContext context, OAuthToken token) + { + string normalizedUrl; + string normalizedRequestParameters; + + var oAuth = new OAuthBase(); + + var nonce = oAuth.GenerateNonce(); + var timeStamp = oAuth.GenerateTimeStamp(); + var sig = oAuth.GenerateSignature(new Uri(baseRequestTokenUrl), + context.ConsumerKey, context.ConsumerSecret, + token == null ? string.Empty : token.TokenKey, token == null ? string.Empty : token.TokenSecret, + method, timeStamp, nonce, + context.SignatureMethod, + out normalizedUrl, out normalizedRequestParameters); + + // + // The signature as self has to be encoded to be ensure that no not url compatibale characters + // will be used. The SHA1 hash can contain a bunch of this characters + // + sig = HttpUtility.UrlEncode(sig); + + var sb = new StringBuilder(normalizedUrl); + + sb.AppendFormat("?"); + sb.AppendFormat(normalizedRequestParameters); + sb.AppendFormat("&oauth_signature={0}", sig); + + return sb.ToString(); + } + + public static string GenerateSignedUrl(string baseResourceUrl, string method, OAuthConsumerContext context, OAuthToken token, Dictionary urlParameter) + { + var sb = new StringBuilder(baseResourceUrl); + + if (urlParameter != null) + { + sb.Append('?'); + + foreach (var kvp in urlParameter) + { + if (sb[sb.Length - 1] == '?') + sb.AppendFormat("{0}={1}", kvp.Key, OAuthBase.UrlEncode(kvp.Value)); + else + sb.AppendFormat("&{0}={1}", kvp.Key, OAuthBase.UrlEncode(kvp.Value)); + } + } + + return GenerateSignedUrl(sb.ToString(), method, context, token); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/OAuthService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/OAuthService.cs new file mode 100644 index 0000000000..405b85af87 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/OAuthService.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web.Http; + + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth +{ + internal class OAuthService : HttpService + { + #region Get Token Method + + private OAuthToken GetToken(string requestTokenUrl) + { + // get the token data + var tokenData = PerformSimpleWebCall(requestTokenUrl, WebRequestMethodsEx.Http.Get, null, null); + + // generate the token as self + return tokenData != null ? OAuthStreamParser.ParseTokenInformation(tokenData) : null; + } + + public OAuthToken GetRequestToken(OAuthServiceContext svcContext, OAuthConsumerContext conContext) + { + var url = OAuthUrlGenerator.GenerateRequestTokenUrl(svcContext.RequestTokenUrl, conContext); + + return GetToken(url); + } + + public OAuthToken GetAccessToken(OAuthServiceContext svcContext, OAuthConsumerContext conContext, OAuthToken requestToken) + { + var url = OAuthUrlGenerator.GenerateAccessTokenUrl(svcContext.AccessTokenUrl, conContext, requestToken); + + return GetToken(url); + } + + #endregion + + #region Special oAuth WebRequest routines + + public virtual WebRequest CreateWebRequest(string url, string method, ICredentials credentials, object context, OAuthConsumerContext conContext, OAuthToken accessToken, Dictionary parameter) + { + // generate the signed url + var signedUrl = GetProtectedResourceUrl(url, conContext, accessToken, parameter, method); + + // generate the web request as self + return CreateWebRequest(signedUrl, method, credentials, false, context); + } + + #endregion + + #region Signed URL helpers + + public string GetProtectedResourceUrl(string resourceUrl, OAuthConsumerContext conContext, OAuthToken accessToken, Dictionary parameter, string webMethod) + { + // build url + return OAuthUrlGenerator.GenerateSignedUrl(resourceUrl, webMethod, conContext, accessToken, parameter); + } + + public string GetSignedUrl(string resourceUrl, OAuthConsumerContext conContext, OAuthToken accessToken, Dictionary parameter) + { + return OAuthUrlGenerator.GenerateSignedUrl(resourceUrl, WebRequestMethodsEx.Http.Post, conContext, accessToken, parameter); + } + + public string GetOAuthAuthorizationHeader(string resourceUrl, OAuthConsumerContext conContext, OAuthToken accessToken, Dictionary parameter, string method) + { + var oAuth = new OAuthBase(); + + string normalizedUrl; + string normalizedRequestParameters; + + var timestamp = oAuth.GenerateTimeStamp(); + var nonce = oAuth.GenerateNonce(); + var signature = oAuth.GenerateSignature(new Uri(resourceUrl), + conContext.ConsumerKey, conContext.ConsumerSecret, + accessToken == null ? string.Empty : accessToken.TokenKey, accessToken == null ? string.Empty : accessToken.TokenSecret, + method, timestamp, nonce, + conContext.SignatureMethod, + out normalizedUrl, out normalizedRequestParameters); + signature = System.Web.HttpUtility.UrlEncode(signature); + + var sb = new StringBuilder("OAuth"); + sb.Append(", oauth_version=1.0"); + sb.AppendFormat(", oauth_nonce={0}", nonce); + sb.AppendFormat(", oauth_timestamp={0}", timestamp); + sb.AppendFormat(", oauth_consumer_key={0}", conContext.ConsumerKey); + if (accessToken != null) + { + sb.AppendFormat(", , oauth_token={0}", accessToken.TokenKey); + } + sb.Append(", oauth_signature_method=\"HMAC-SHA1\""); + sb.AppendFormat(", oauth_signature={0}", signature); + + return sb.ToString(); + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Token/OAuthToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Token/OAuthToken.cs new file mode 100644 index 0000000000..7a52a24796 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth/Token/OAuthToken.cs @@ -0,0 +1,32 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token +{ + /// + /// The OAuthToken will be generated during the login process in a oauth compliant + /// application and can be used to sign the url + /// + internal class OAuthToken + { + /// + /// The key for uri signing + /// + public string TokenKey { get; protected set; } + + /// + /// The secret for uri signing + /// + public string TokenSecret { get; protected set; } + + /// + /// The token can only be generated from our API + /// + /// + /// + internal OAuthToken(string tokenKey, string tokenSecret) + { + TokenKey = tokenKey; + TokenSecret = tokenSecret; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth20/OAuth20Token.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth20/OAuth20Token.cs new file mode 100644 index 0000000000..ffe0894417 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Common/Net/oAuth20/OAuth20Token.cs @@ -0,0 +1,86 @@ +using System; +using System.Text; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; + +namespace AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20 +{ + public class OAuth20Token : ICloudStorageAccessToken + { + public string AccessToken { get; set; } + + public string RefreshToken { get; set; } + + public double ExpiresIn { get; set; } + + public string ClientID { get; set; } + + public string ClientSecret { get; set; } + + public string RedirectUri { get; set; } + + public DateTime? Timestamp { get; set; } + + public bool IsExpired + { + get + { + if (Timestamp.HasValue && !ExpiresIn.Equals(default(double))) + return DateTime.UtcNow > Timestamp + TimeSpan.FromSeconds(ExpiresIn); + return true; + } + } + + public static OAuth20Token FromJson(string json) + { + var parser = new JsonHelper(); + + if (!parser.ParseJsonMessage(json)) + return null; + + var accessToken = parser.GetProperty("access_token"); + var refreshToken = parser.GetProperty("refresh_token"); + + if (string.IsNullOrEmpty(accessToken)) + return null; + + var token = new OAuth20Token + { + AccessToken = accessToken, + RefreshToken = refreshToken, + ClientID = parser.GetProperty("client_id"), + ClientSecret = parser.GetProperty("client_secret"), + RedirectUri = parser.GetProperty("redirect_uri"), + }; + + double expiresIn; + if (double.TryParse(parser.GetProperty("expires_in"), out expiresIn)) + token.ExpiresIn = expiresIn; + + DateTime timestamp; + if (DateTime.TryParse(parser.GetProperty("timestamp"), out timestamp)) + token.Timestamp = timestamp; + + return token; + } + + public string ToJson() + { + var sb = new StringBuilder(); + sb.Append("{"); + sb.AppendFormat(" \"access_token\": \"{0}\"", AccessToken); + sb.AppendFormat(", \"refresh_token\": \"{0}\"", RefreshToken); + sb.AppendFormat(", \"expires_in\": \"{0}\"", ExpiresIn); + sb.AppendFormat(", \"client_id\": \"{0}\"", ClientID); + sb.AppendFormat(", \"client_secret\": \"{0}\"", ClientSecret); + sb.AppendFormat(", \"redirect_uri\": \"{0}\"", RedirectUri); + sb.AppendFormat(", \"timestamp\": \"{0}\"", Timestamp); + sb.Append("}"); + return sb.ToString(); + } + + public override string ToString() + { + return RefreshToken; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.Designer.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.Designer.cs new file mode 100644 index 0000000000..520e8baba6 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.Designer.cs @@ -0,0 +1,180 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18052 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace AppLimit.CloudComputing.SharpBox.Exceptions { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ErrorMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ErrorMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AppLimit.CloudComputing.SharpBox.Exceptions.ErrorMessages", typeof(ErrorMessages).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Couldn't contact storage service. + /// + internal static string ErrorCouldNotContactStorageService { + get { + return ResourceManager.GetString("ErrorCouldNotContactStorageService", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Couldn't retrieve child elements from the server. + /// + internal static string ErrorCouldNotRetrieveDirectoryList { + get { + return ResourceManager.GetString("ErrorCouldNotRetrieveDirectoryList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Instancing the cloud storage provider failed, verify the inner exception. + /// + internal static string ErrorCreateProviderInstanceFailed { + get { + return ResourceManager.GetString("ErrorCreateProviderInstanceFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File not found. + /// + internal static string ErrorFileNotFound { + get { + return ResourceManager.GetString("ErrorFileNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No more space in cloud storage available. + /// + internal static string ErrorInsufficientDiskSpace { + get { + return ResourceManager.GetString("ErrorInsufficientDiskSpace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The gived consumer Key/Secret are invalid. + /// + internal static string ErrorInvalidConsumerKeySecret { + get { + return ResourceManager.GetString("ErrorInvalidConsumerKeySecret", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The gived credentials or configuration format does not fits to the storage provider. + /// + internal static string ErrorInvalidCredentialsOrConfiguration { + get { + return ResourceManager.GetString("ErrorInvalidCredentialsOrConfiguration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid file or directory name. + /// + internal static string ErrorInvalidFileOrDirectoryName { + get { + return ResourceManager.GetString("ErrorInvalidFileOrDirectoryName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One or more parameters are invalid. + /// + internal static string ErrorInvalidParameters { + get { + return ResourceManager.GetString("ErrorInvalidParameters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configured file size limit for transfer exceeded. + /// + internal static string ErrorLimitExceeded { + get { + return ResourceManager.GetString("ErrorLimitExceeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No valid storage provider was found for the given configuration type. + /// + internal static string ErrorNoValidProviderFound { + get { + return ResourceManager.GetString("ErrorNoValidProviderFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The operation needs an opened connection to the cloud storage, please call the open method before!. + /// + internal static string ErrorOpenedConnectionNeeded { + get { + return ResourceManager.GetString("ErrorOpenedConnectionNeeded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The datatransfer was interrupted from the application during a callback. + /// + internal static string ErrorTransferAbortedManually { + get { + return ResourceManager.GetString("ErrorTransferAbortedManually", resourceCulture); + } + } + } +} diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.resx b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.resx new file mode 100644 index 0000000000..74ea09e4d1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/ErrorMessages.resx @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Couldn't contact storage service + + + Couldn't retrieve child elements from the server + + + Instancing the cloud storage provider failed, verify the inner exception + + + File not found + + + No more space in cloud storage available + + + The gived consumer Key/Secret are invalid + + + The gived credentials or configuration format does not fits to the storage provider + + + Invalid file or directory name + + + One or more parameters are invalid + + + Configured file size limit for transfer exceeded + + + No valid storage provider was found for the given configuration type + + + The operation needs an opened connection to the cloud storage, please call the open method before! + + + The datatransfer was interrupted from the application during a callback + + \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxErrorCodes.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxErrorCodes.cs new file mode 100644 index 0000000000..30e1f422be --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxErrorCodes.cs @@ -0,0 +1,99 @@ +namespace AppLimit.CloudComputing.SharpBox.Exceptions +{ + /// + /// This enum contains all existing error codes + /// which can be used in a SharpBoxException + /// + public enum SharpBoxErrorCodes + { + /// + /// This error occurs when the cloud storage + /// service will be not available via network + /// + ErrorCouldNotContactStorageService = 1, + + /// + /// This error occurs when a given path is not + /// in the correct format, e.g. a directory is + /// needed but the path targets a files + /// + ErrorInvalidFileOrDirectoryName = 2, + + /// + /// This error occurs when a file or path was + /// not found behind the given location + /// + ErrorFileNotFound = 3, + + /// + /// This error occurs when a cloud storage service + /// provider was not registered for a specific + /// configuration + /// + ErrorNoValidProviderFound = 4, + + /// + /// This error occurs when the creation of a + /// cloud storage service provider was not + /// possible. This can happens when the author of + /// a provider is doing complex things in the + /// constructor of the class + /// + ErrorCreateProviderInstanceFailed = 5, + + /// + /// This error occurs when the give credentials, e.g. + /// Password, UserName, ApplicationKey are wrong + /// + ErrorInvalidCredentialsOrConfiguration = 6, + + /// + /// This error occures when one or more parameters + /// of the called function was wrong + /// + ErrorInvalidParameters = 7, + + /// + /// This error occurs when the client can't request + /// the directory childs from the server + /// + ErrorCouldNotRetrieveDirectoryList = 8, + + /// + /// This error occurs when a create operation + /// failed + /// + ErrorCreateOperationFailed = 9, + + /// + /// This error occurs when a configured limit + /// exceeds + /// + ErrorLimitExceeded = 10, + + /// + /// This error occures when the storage limit of + /// the cloud storage is exceeded + /// + ErrorInsufficientDiskSpace = 11, + + /// + /// The datatransfer was interrupted from the + /// application during a callback + /// + ErrorTransferAbortedManually = 12, + + /// + /// The operation needs an opened connection + /// to the cloud storage, please call the + /// open method before! + /// + ErrorOpenedConnectionNeeded = 13, + + /// + /// This error occurs when consumer + /// Key/Secret pair are not valid + /// + ErrorInvalidConsumerKeySecret = 14 + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxException.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxException.cs new file mode 100644 index 0000000000..0f60d627f1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/Exceptions/SharpBoxException.cs @@ -0,0 +1,94 @@ +using System; +using System.Net; +using System.Runtime.Serialization; + +namespace AppLimit.CloudComputing.SharpBox.Exceptions +{ + /// + /// The SharpBoxException class implements the error code and error + /// message of a specific sharp box error. Catch this kind of exceptions + /// to get all sharpbox related error in the application + /// + [Serializable] + public class SharpBoxException : Exception + { + /// + /// This property contains the errorcode of the specific sharpbox error + /// + public SharpBoxErrorCodes ErrorCode { get; private set; } + + /// + /// This property contains the used webrequest which throws the exception + /// + public WebRequest PostedRequet { get; private set; } + + /// + /// This property contains a disposed webresponse which received during + /// network operation which throws this exception + /// + public WebResponse DisposedReceivedResponse { get; private set; } + + /// + /// The constructure if the SharpBoxException class. The error code wil + /// be resolved into an text message automatically + /// + /// + public SharpBoxException(SharpBoxErrorCodes errorCode) + : this(errorCode, null) + { + } + + /// + /// The constructure if the SharpBoxException class. The error code wil + /// be resolved into an text message automatically + /// + /// + /// + internal SharpBoxException(SharpBoxErrorCodes errorCode, Exception innerException) + : this(errorCode, innerException, null, null) + { + } + + internal SharpBoxException(SharpBoxErrorCodes errorCode, Exception innerException, WebRequest request, WebResponse response) + : base(GetErrorMessage(errorCode), innerException) + { + ErrorCode = errorCode; + PostedRequet = request; + DisposedReceivedResponse = response; + } + + protected SharpBoxException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + private static string GetErrorMessage(SharpBoxErrorCodes errorCode) + { + // get the key + var key = errorCode.ToString(); + + // Load the value of string value for Client + try + { + return ErrorMessages.ResourceManager.GetString(key); + } + catch (Exception) + { + return "n/a"; + } + } + + internal static void ThrowSharpBoxExceptionBasedOnNetworkErrorCode(WebRequest uploadRequest, int code, WebException e) + { + if (Convert.ToInt32(code) == 507) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInsufficientDiskSpace, e, uploadRequest, null); + + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCreateOperationFailed, e, uploadRequest, null); + } + + internal static void ThrowSharpBoxExceptionBasedOnHttpErrorCode(HttpWebRequest uploadRequest, HttpStatusCode code, WebException e) + { + ThrowSharpBoxExceptionBasedOnNetworkErrorCode(uploadRequest, (int)code, e); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudDirectoryEntry.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudDirectoryEntry.cs new file mode 100644 index 0000000000..5a9588577d --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudDirectoryEntry.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This structure defines the different states which are possible + /// about the child state + /// + public enum nChildState + { + /// + /// Indicates that the folder has some childs (folders or files) + /// + HasChilds = 1, + + /// + /// Indicates that the folder has no childs (folders or files) + /// + HasNoChilds = 2, + + /// + /// Indicates that SharpBox did not evaluated it. To evaluate this + /// just call GetChild + /// + HasNotEvaluated = 3 + } + + /// + /// Normally file based storage systems are supporting a hierarchical + /// folder structure. This interface will be used to get access on the + /// folders in the cloud storage + /// + public interface ICloudDirectoryEntry : ICloudFileSystemEntry, IEnumerable + { + /// + /// This method allows to get a directory entry with a specific folder + /// id. + /// + /// The name of the targeted folder + /// Reference to the file or folder + ICloudFileSystemEntry GetChild(string id); + + /// + /// This method allows to get a directory entry with a specific folder + /// id. + /// + /// + /// + /// + ICloudFileSystemEntry GetChild(string id, bool bThrowException); + + /// + /// This method allows to get a directory entry with a specific index + /// number + /// + /// The index of the targeted folder + /// Reference to the file or folder + ICloudFileSystemEntry GetChild(int idx); + + /// + /// This property allows to access to the number of + /// child items + /// + int Count { get; } + + /// + /// This property contains the information about the children state. Query this property + /// will not perform any network operations + /// + nChildState HasChildrens { get; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileDataTransfer.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileDataTransfer.cs new file mode 100644 index 0000000000..f2b8eb46c3 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileDataTransfer.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; +using System.Runtime.Serialization; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This enum describes the data transfer direction + /// + public enum nTransferDirection + { + /// + /// Defines that the target data stream should be uploaded into the cloud file container + /// + nUpload, + + /// + /// Defines that the data from the cloud file container should be downloaded into the target data stream + /// + nDownload + }; + + + /// + /// This class contains the arguments which can be used when a data transfer operation is running + /// + public class FileDataTransferEventArgs : EventArgs, ICloneable + { + /// + /// Set this to true to abort the transfer + /// + public bool Cancel { get; set; } + + /// + /// The amount of bytes currently transfered + /// + public long CurrentBytes { get; internal set; } + + /// + /// The amount of bytes which has to be transfered in total + /// + public long TotalBytes { get; internal set; } + + /// + /// Overall progress in % + /// + public int PercentageProgress { get; internal set; } + + /// + /// The calculated transfer rate for this operation overall(Kbits/s) + /// + public long TransferRateTotal { get; internal set; } + + /// + /// The current messured transfer rate (Kbits/s) + /// + public long TransferRateCurrent { get; internal set; } + + /// + /// The estimated finish time if this transfer + /// + public TimeSpan OpenTransferTime { get; internal set; } + + /// + /// A reference to the associated cloud file system entry + /// + public ICloudFileSystemEntry FileSystemEntry { get; internal set; } + + /// + /// A use specific context + /// + public object CustomnContext { get; internal set; } + + /// + /// ctor + /// + public FileDataTransferEventArgs() + { + Cancel = false; + } + + #region ICloneable Members + + /// + /// This method implements to clone interface to support a deep copy + /// of everything what we use to report the progress of a operation + /// + /// + public object Clone() + { + var e = new FileDataTransferEventArgs + { + CurrentBytes = CurrentBytes, + CustomnContext = CustomnContext, + FileSystemEntry = FileSystemEntry, + OpenTransferTime = OpenTransferTime, + PercentageProgress = PercentageProgress, + TotalBytes = TotalBytes, + TransferRateCurrent = TransferRateCurrent, + TransferRateTotal = TransferRateTotal, + Cancel = false + }; + + return e; + } + + #endregion + } + + /// + /// This delegate can be used as callback for upload or download operation in the + /// data streams. + /// + /// sender object of the event + /// event args + public delegate void FileOperationProgressChanged(object sender, FileDataTransferEventArgs e); + + /// + /// This interface implements a specifc transfer logic which can be used + /// to transport data from a local data stream to a remote filesystem entry + /// and back + /// + public interface ICloudFileDataTransfer + { + /// + /// This method transfers data between a local data stream and the remote filesystem entry on + /// byte level + /// + /// + /// + void Transfer(Stream targetDataStream, nTransferDirection direction); + + /// + /// This method transfers data between a local data stream and the remote filesystem entry on + /// byte level + /// + /// + /// + /// + /// + void Transfer(Stream targetDataStream, nTransferDirection direction, FileOperationProgressChanged progressCallback, object progressContext); + + /// + /// This method transfers data between a local data stream and the remote filesystem entry on + /// byte level. This API triggers the callback in an async manner this means the transfer process + /// is not blocked during the consumer is in the handler + /// + /// + /// + /// + /// + void TransferAsyncProgress(Stream targetDataStream, nTransferDirection direction, FileOperationProgressChanged progressCallback, object progressContext); + + /// + /// Allows native access to the download stream of the associated file. + /// Ensure that this stream will be disposed clearly! + /// + Stream GetDownloadStream(); + + /// + /// Allows native access to the upload stream of the associated file + /// Ensure that this stream will be disposed clearly! + /// + /// + Stream GetUploadStream(long uploadSize); + + /// + /// This method supports the serialization of object graphs into the remote file container + /// + /// + /// + void Serialize(IFormatter dataFormatter, object objectGraph); + + /// + /// This method allows to deserialize an object graph from the remote file container + /// + /// + /// + object Deserialize(IFormatter dataFormatter); + + IResumableUploadSession CreateResumableSession(long bytesToTransfer); + + void AbortResumableSession(IResumableUploadSession transferSession); + + void Transfer(IResumableUploadSession transferSession, Stream data, long dataLength); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileSystemEntry.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileSystemEntry.cs new file mode 100644 index 0000000000..5b1e8b9fed --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudFileSystemEntry.cs @@ -0,0 +1,58 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// Normally file based storage systems are supporting file system + /// entries. This interface will be used to get access on the + /// file system entry in the cloud storage + /// + public interface ICloudFileSystemEntry + { + /// + /// The name of the associated folder + /// + string Name { get; } + + /// + /// This attribute contains uniq id of the entry. Id = Name for most providers + /// + string Id { get; } + + /// + /// This attribute contains the size of a file or the count of childs + /// of the associated directory + /// + long Length { get; } + + /// + /// This attribute contains the modification date of the object + /// + DateTime Modified { get; } + + /// + /// ID of the parent folder. + /// + string ParentID { get; set; } + + /// + /// The parent folder of the associated folder, can be null if it's + /// the root folder + /// + ICloudDirectoryEntry Parent { get; set; } + + /// + /// This method return an implementation of an content data transfer interface + /// + /// + ICloudFileDataTransfer GetDataTransferAccessor(); + + /// + /// This method gives raw access to the properties of the specific + /// protocol provider + /// + /// + /// + string GetPropertyValue(string key); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAccessToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAccessToken.cs new file mode 100644 index 0000000000..02b9e793c9 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAccessToken.cs @@ -0,0 +1,10 @@ +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// Many cloud storages allow a token based authentication. This interface is used to implement + /// an access token structure + /// + public interface ICloudStorageAccessToken + { + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAsyncInterface.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAsyncInterface.cs new file mode 100644 index 0000000000..d99626452c --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageAsyncInterface.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This interface defines all methods which has to be implemented + /// to support asynchoniously I/O, e.g. for WP7 + /// + public interface ICloudStorageAsyncInterface + { + /// + /// The BeginOpenRequest-Method starts the authentication process of a given user with the + /// configured cloud storage service. After finishing this process in the background + /// the callback delegate will be executed. Please use EndOpenRequest in the callback + /// delegate + /// + /// Delegate which will be called when the background action is finished + /// The configuration information of the cloud storage service + /// The credential token of the user which has to be authenticated + /// The asyncresult is the entry point to all generated results + IAsyncResult BeginOpenRequest(AsyncCallback callback, ICloudStorageConfiguration configuration, ICloudStorageAccessToken token); + + /// + /// The EndOpenRequest method will finish a started async call. Please use this + /// method in the callback delegate. + /// + /// The result reference generated by BeginOpenRequest + /// The generated cloud access token + ICloudStorageAccessToken EndOpenRequest(IAsyncResult asyncResult); + + /// + /// The BeginGetChildsRequest-Method starts retrieving the list of childs of a given + /// parent container. This procedure can take a while if some information has to + /// be requested from the network + /// + /// + /// + /// + IAsyncResult BeginGetChildsRequest(AsyncCallback callback, ICloudDirectoryEntry parent); + + /// + /// The EndGetChildsRequest-Method will finish a started async call. Please use this + /// method in the callback delegate. + /// + /// + /// + List EndGetChildsRequest(IAsyncResult asyncResult); + + /// + /// The begin routine the receive the root element from cloud storage + /// + /// + /// + IAsyncResult BeginGetRootRequest(AsyncCallback callback); + + /// + /// The end routine the receive the root element + /// + /// + /// + ICloudDirectoryEntry EndGetRootRequest(IAsyncResult asyncResult); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageConfiguration.cs new file mode 100644 index 0000000000..46a92e59a3 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageConfiguration.cs @@ -0,0 +1,30 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This interface has to be implemented from storage providers to support + /// access configuration information. Consumers of this library has to create + /// an instance of a provider specific implementation to build up a connection + /// to the CloudStorage + /// + public interface ICloudStorageConfiguration + { + /// + /// Contains the url of the specific service which will be used from + /// storage service provider + /// + Uri ServiceLocator { get; } + + /// + /// If true this value indicates the all ssl connection are valid. This means also ssl connection + /// with an invalid certificate will be accepted. + /// + bool TrustUnsecureSSLConnections { get; } + + /// + /// Contains the limits of a specific cloud storage connection + /// + CloudStorageLimits Limits { get; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageProvider.cs new file mode 100644 index 0000000000..600db59ebb --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStorageProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace AppLimit.CloudComputing.SharpBox +{ + public interface ICloudStorageProvider + { + ICloudStorageAccessToken CurrentAccessToken { get; } + + ICloudStorageAccessToken Open(ICloudStorageConfiguration configuration, ICloudStorageAccessToken token); + + void Close(); + + ICloudDirectoryEntry GetRoot(); + + ICloudFileSystemEntry GetFileSystemObject(string path, ICloudDirectoryEntry parent); + + ICloudDirectoryEntry CreateFolder(string name, ICloudDirectoryEntry parent); + + bool DeleteFileSystemEntry(ICloudFileSystemEntry fsentry); + + bool MoveFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent); + + bool CopyFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent); + + bool RenameFileSystemEntry(ICloudFileSystemEntry fsentry, string newName); + + ICloudFileSystemEntry CreateFile(ICloudDirectoryEntry parent, string name); + + Uri GetFileSystemObjectUrl(string path, ICloudDirectoryEntry parent); + + string GetFileSystemObjectPath(ICloudFileSystemEntry fsObject); + } + + internal interface ICloudStorageProviderInternal : ICloudStorageProvider + { + ICloudStorageAccessToken LoadToken(Dictionary tokendata); + + void StoreToken(Dictionary tokendata, ICloudStorageAccessToken token); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStoragePublicAPI.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStoragePublicAPI.cs new file mode 100644 index 0000000000..6aef91658f --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/ICloudStoragePublicAPI.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox +{ + /// + /// This enum describes all support cloud storage provider + /// configuration in sharpbox. This enum will also be used + /// to implement a service chooser in the future + /// + public enum nSupportedCloudConfigurations + { + /// + /// DropBox + /// + DropBox, + + /// + /// StoreGate + /// + StoreGate, + + /// + /// BoxNet + /// + BoxNet, + + /// + /// SmartDrive + /// + SmartDrive, + + /// + /// WebDav + /// + WebDav, + + /// + /// CloudMe + /// + CloudMe, + + /// + /// Strato HiDrive + /// + HiDrive, + + /// + /// Google Drive + /// + Google, + + /// + /// Yandex.Disk + /// + Yandex, + + /// + /// SkyDrive + /// + SkyDrive + } + + public interface ICloudStoragePublicAPI : ICloudStorageProvider, ICloudStorageAsyncInterface + { + bool IsOpened { get; } + + #region Security Token Handling + + Stream SerializeSecurityToken(ICloudStorageAccessToken token); + + Stream SerializeSecurityToken(ICloudStorageAccessToken token, Dictionary additionalMetaData); + + Stream SerializeSecurityTokenEx(ICloudStorageAccessToken token, Type configurationType, Dictionary additionalMetaData); + + ICloudStorageAccessToken DeserializeSecurityToken(Stream tokenStream); + + ICloudStorageAccessToken DeserializeSecurityToken(Stream tokenStream, out Dictionary additionalMetaData); + + #endregion + + #region Comfort Functions + + ICloudDirectoryEntry GetFolder(string path); + + ICloudDirectoryEntry GetFolder(string path, ICloudDirectoryEntry parent); + + ICloudDirectoryEntry GetFolder(string path, bool throwException); + + ICloudDirectoryEntry GetFolder(string path, ICloudDirectoryEntry startFolder, bool throwException); + + ICloudFileSystemEntry GetFile(string path, ICloudDirectoryEntry startFolder); + + void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath); + + void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath, FileOperationProgressChanged delProgress); + + void DownloadFile(string filePath, string targetPath); + + void DownloadFile(string filePath, string targetPath, FileOperationProgressChanged delProgress); + + void DownloadFile(string name, ICloudDirectoryEntry parent, Stream targetStream); + + ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer); + + ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, FileOperationProgressChanged delProgress); + + ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, string targetFileName); + + ICloudFileSystemEntry UploadFile(string filePath, ICloudDirectoryEntry targetContainer, string targetFileName, FileOperationProgressChanged delProgress); + + ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory); + + ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, FileOperationProgressChanged delProgress); + + ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, string targetFileName); + + ICloudFileSystemEntry UploadFile(string filePath, string targetDirectory, string targetFileName, FileOperationProgressChanged delProgress); + + ICloudFileSystemEntry UploadFile(Stream uploadDataStream, string targetFileName, ICloudDirectoryEntry targetContainer, FileOperationProgressChanged delProgress); + + ICloudFileSystemEntry UploadFile(Stream uploadDataStream, string targetFileName, ICloudDirectoryEntry targetContainer); + + ICloudDirectoryEntry CreateFolder(string path); + + ICloudDirectoryEntry CreateFolderEx(string path, ICloudDirectoryEntry entry); + + bool DeleteFileSystemEntry(string filePath); + + bool MoveFileSystemEntry(string filePath, string newParentPath); + + bool RenameFileSystemEntry(string filePath, string newName); + bool CopyFileSystemEntry(string filePath, string newParentPath); + ICloudFileSystemEntry CreateFile(string filePath); + + #endregion + + #region Configuration Mapping + + ICloudStorageConfiguration GetCloudConfiguration(nSupportedCloudConfigurations configtype, params object[] param); + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/IResumableUploadSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/IResumableUploadSession.cs new file mode 100644 index 0000000000..0a9bdd9b14 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/IResumableUploadSession.cs @@ -0,0 +1,29 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox +{ + public enum ResumableUploadSessionStatus + { + None, + Started, + Completed, + Aborted + } + + public interface IResumableUploadSession + { + long BytesToTransfer { get; } + + long BytesTransfered { get; } + + ICloudFileSystemEntry File { get; } + + ResumableUploadSessionStatus Status { get; } + + DateTime CreatedOn { get; } + + object GetItem(string key); + + T GetItem(string key); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/Resources/loader.gif b/thirdparty/AppLimit.CloudComputing.SharpBox/Resources/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..eab55078feb56ed6993c181e6ba111689ff1f515 GIT binary patch literal 2599 zcmdVb`&X0a0SE9WZ!RQ+TzSb2A_0N2a*?7Uu5JhNLV!#l5lZ9I3*jZ<4c=lJEthpd z1qClH3uGv?9eAAZ-EQyi@9*mBYH4Y4xm*^DrJU`1bS_39h6{?DM?os7O zYj0FJ}sW5=nKr2K;Nb*Z|u*E)4+ zI->(HbkfhR5uI}`HIZPSquhK~G2yuW9yBsHriO3>4yz6adKKr7&D%pq%FJ3-+<@TY zx2B$XH7j_b&_KMwOx`}e<;eM{@`ELO7Ix&T!!6GyZs&;_-t=lui!XCp_Ezhy(m0eb zaJFhP!;cZajxn^NAyl(p!#|v%K;LiFl)xiH|1w%GiP`#IwUyH;TuZ9{Qq~hwaJ#Bf zOv@c&sW;v0bk6-r14L9gWml2%TOJ05PE!IH4iqNk<$Hh%SDS$KG-K3lRAzoO!_vs|R3}Ya#T`*z8SQ41?HD(xVb-t$dryMkL$kT^ zkug@t8v<^wuia~sS6j=QIGN`~mqwO4y7y92=)+aDuBPf7_reLEXm^n?t+(xp@6QuG z5&OOn{l7r_UQ7B(Gn3)_oyYjA5Be1l&)C==e>K&nL?C5!aY9W58uq zWL}uQh|0{0vxD8}IY4Ud5|+Iv!&$zTOmk_(co~2TQ=2y_*ikKN976KuabIbM+ZhRI zd?XM4`Z7HL1S4-Y4KL0)>!z7E&1X~D*4EnANrsD zh%x$KM&-h;)2PR&t`a&72|hBc7(yL2V&czIC(5i4oKh3=@>3&FEkYo{+9hgLO?b-g znO2R}t4{R7?tr$_!^9JCe#;Ygv-J?8?g=3S+28zeMQHk|$)AdmFMR8k%y~me^mEg-_BJ|ncbtg6b(gU~ zKs)U&Wjabf#9fQdG~#Ka;y(Itp|VKZTdx_(^0W@G>7NAY28$6XK+Vz@-9hDxaw|* zt6ub9oeZLA6XhSpoxP;p8Lo%~R`(j8Y3+Su)SgSX6N9(B^c&Cmmo(?%6CPRmuaYBH zinkY(l7Y{@BntH*^@u%k2=cfs z%+uhdtPc@ZDGt)ptVzGepm#9(6-08Hpl_I>=m|tUV@k}>6X&K}*zDXqw)N)143@5+ zoSW9#u(7$TFJ}%;4eOgG#90xF=*|70&3MmzBVuz8h({{`6eDjV1;uYnVqK1=1%y0` zJ7W)xKH2iusj(VnE283ABHg_Vf8tSc&ja!3{D@y|sUu{4OgHuFx`mRBw=Q@l?s?C| GJ^y#b`>##_ literal 0 HcmV?d00001 diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericHelper.cs new file mode 100644 index 0000000000..4dac26c273 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericHelper.cs @@ -0,0 +1,30 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API +{ + internal class GenericHelper + { + public static string GetResourcePath(ICloudFileSystemEntry entry) + { + var current = entry; + var path = ""; + + while (current != null) + { + if (current.Name != "/") + { + if (path == string.Empty) + path = current.Id; + else + path = current.Id + "/" + path; + } + else + path = "/" + path; + + current = current.Parent; + } + + return path; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericStorageProviderFactory.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericStorageProviderFactory.cs new file mode 100644 index 0000000000..93febd02a5 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/GenericStorageProviderFactory.cs @@ -0,0 +1,146 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API +{ + /// + /// This class allows to create the needed object which are internally used to create + /// extern storage providers + /// + public class GenericStorageProviderFactory + { + /// + /// This method builds an object + /// + /// + /// + /// + /// + public static ICloudFileSystemEntry CreateFileSystemEntry(IStorageProviderSession session, string Name, ICloudDirectoryEntry parent) + { + return CreateFileSystemEntry(session, Name, DateTime.Now, 0, parent); + } + + /// + /// This method creates a filesystem entry + /// + /// + /// + /// + /// + /// + /// + public static ICloudFileSystemEntry CreateFileSystemEntry(IStorageProviderSession session, string Name, DateTime modified, long fileSize, ICloudDirectoryEntry parent) + { + // build up query url + var newObj = new BaseFileEntry(Name, fileSize, modified, session.Service, session); + + // case the parent if possible + if (parent != null) + { + var objparent = parent as BaseDirectoryEntry; + objparent.AddChild(newObj); + } + + return newObj; + } + + /// + /// This method clears all childs of a directory entry + /// + /// + public static void ClearAllChilds(ICloudDirectoryEntry dir) + { + (dir as BaseDirectoryEntry).ClearChilds(); + } + + /// + /// + /// + /// + /// + /// + /// + public static ICloudDirectoryEntry CreateDirectoryEntry(IStorageProviderSession session, string Name, ICloudDirectoryEntry parent) + { + return CreateDirectoryEntry(session, Name, DateTime.Now, parent); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static ICloudDirectoryEntry CreateDirectoryEntry(IStorageProviderSession session, string Name, DateTime modifiedDate, ICloudDirectoryEntry parent) + { + // build up query url + var newObj = new BaseDirectoryEntry(Name, 0, modifiedDate, session.Service, session); + + // case the parent if possible + if (parent != null) + { + var objparent = parent as BaseDirectoryEntry; + objparent.AddChild(newObj); + } + + return newObj; + } + + /// + /// + /// + /// + /// + public static void DeleteFileSystemEntry(IStorageProviderSession session, ICloudFileSystemEntry objectToRemove) + { + // get the parent dir + var parentDir = objectToRemove.Parent as BaseDirectoryEntry; + + // remove from parent + parentDir.RemoveChild(objectToRemove as BaseFileEntry); + } + + /// + /// + /// + /// + /// + /// + public static void MoveFileSystemEntry(IStorageProviderSession session, ICloudFileSystemEntry objectToMove, ICloudDirectoryEntry newParent) + { + // readjust parent + var oldParent = objectToMove.Parent as BaseDirectoryEntry; + oldParent.RemoveChild(objectToMove as BaseFileEntry); + + var newParentObject = newParent as BaseDirectoryEntry; + newParentObject.AddChild(objectToMove as BaseFileEntry); + } + + /// + /// + /// + /// + /// + /// + public static void RenameFileSystemEntry(IStorageProviderSession session, ICloudFileSystemEntry objectToRename, string newName) + { + // rename the fsentry + var fentry = objectToRename as BaseFileEntry; + fentry.Name = newName; + } + + /// + /// + /// + /// + /// + public static void ModifyFileSystemEntryLength(ICloudFileSystemEntry fsentry, long newLength) + { + var fs = (BaseFileEntry)fsentry; + fs.Length = newLength; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderService.cs new file mode 100644 index 0000000000..bd1fb3a6cf --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderService.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API +{ + /// + /// This interface is part of the sharpbox extensability api + /// and has to be implemented as main entry point for an + /// existing service + /// + public interface IStorageProviderService + { + /// + /// Checks if the given token are valid for using with this + /// service + /// + /// + /// + /// + bool VerifyAccessTokenType(ICloudStorageAccessToken token); + + /// + /// establishing a new session via access token + /// + /// + /// + /// + IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration); + + /// + /// This method closes a created session + /// + /// + void CloseSession(IStorageProviderSession session); + + CloudStorageLimits GetLimits(IStorageProviderSession session); + + /// + /// Requests all resource information via webcall + /// + /// + /// + /// + /// + ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent); + + /// + /// This method refreshes the metadata of an resource + /// + /// + /// + void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource); + + /// + /// Creates or updates a resource via webcall + /// + /// + /// + /// + /// + ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent); + + /// + /// Removes a specific resource from the web location + /// + /// + /// + bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry); + + /// + /// Moves a give resource from one location to an other + /// + /// + /// + /// + /// + bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent); + + + /// + /// Copy a give resource from one location to an other + /// + /// + /// + /// + /// + bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent); + + /// + /// Renames a give resource + /// + /// + /// + /// + /// + bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName); + + /// + /// Receives the information which are stored in a token + /// + /// + /// + /// + void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token); + + /// + /// Loads the information from a token stream + /// + ICloudStorageAccessToken LoadToken(Dictionary tokendata); + + /// + /// The method returns the url to a specific resource + /// + /// + /// + /// + /// + string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, string additionalPath); + + /// + /// This interface implements the download code + /// + /// + /// + /// + /// + /// + void DownloadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext); + + /// + /// Allows the access to the download stream directly + /// + /// + /// + /// + Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry); + + /// + /// This method is called when the stream operation is finished but before the + /// dispose method of the stream will be called + /// + /// + /// + /// + /// + void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream); + + /// + /// This interface implements the upload code + /// + /// + /// + /// + /// + /// + void UploadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext); + + /// + /// Allows the access to the upload stream directly + /// + /// + /// + /// + /// + Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize); + + bool SupportsDirectRetrieve { get; } + + bool SupportsChunking { get; } + + IResumableUploadSession CreateUploadSession(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long bytesToTransfer); + + void AbortUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession); + + void UploadChunk(IStorageProviderSession session, IResumableUploadSession uploadSession, Stream stream, long chunkLength); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderSession.cs new file mode 100644 index 0000000000..695f601f79 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/API/IStorageProviderSession.cs @@ -0,0 +1,26 @@ +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.API +{ + /// + /// This interface is part of the managed storage provider API + /// and implements an authenticated session + /// + public interface IStorageProviderSession + { + /// + /// The generated access token for this + /// session + /// + ICloudStorageAccessToken SessionToken { get; } + + /// + /// The associated service which is connected + /// with this session + /// + IStorageProviderService Service { get; } + + /// + /// A valid cloud storage service configuration + /// + ICloudStorageConfiguration ServiceConfiguration { get; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseDirectoryEntry.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseDirectoryEntry.cs new file mode 100644 index 0000000000..7680f911b4 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseDirectoryEntry.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects +{ + internal class BaseDirectoryEntry : BaseFileEntry, ICloudDirectoryEntry + { + private Dictionary _subDirectories = new Dictionary(StringComparer.OrdinalIgnoreCase); + private List _subDirectoriesByIndex = new List(); + private bool _subDirectoriesRefreshedInitially; + + public BaseDirectoryEntry(string name, long Length, DateTime modified, IStorageProviderService service, IStorageProviderSession session) + : base(name, Length, modified, service, session) + { + } + + #region ICloudDirectoryEntry Members + + public ICloudFileSystemEntry GetChild(string id) + { + return GetChild(id, true); + } + + public ICloudFileSystemEntry GetChild(string id, bool bThrowException) + { + // refresh this item to ensure that the parents + // are valud + RefreshResource(); + + // query subitems + ICloudFileSystemEntry pe; + _subDirectories.TryGetValue(id, out pe); + + // send the exception if needed + if (bThrowException && pe == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + // go ahead + return pe; + } + + public ICloudFileSystemEntry GetChild(int idx) + { + // refresh this item to ensure that the parents + // are valud + RefreshResource(); + + // request the information + return idx < _subDirectoriesByIndex.Count ? _subDirectoriesByIndex[idx] : null; + } + + public int Count + { + get + { + // go ahead + return _subDirectories.Count; + } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + // refresh this item to ensure that the parents + // are valud + RefreshResource(); + + // go ahead + return _subDirectories.Values.GetEnumerator(); + } + + internal IEnumerable GetSubdirectoriesWithoutRefresh() + { + // go ahead + return _subDirectories.Values; + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + + public void AddChild(BaseFileEntry child) + { + // remove child if available + //RemoveChild(child); + + //don't need to remove child if contains; it's must be up to date due ProviderService's + if (_subDirectories.ContainsKey(child.Id)) + { + child.Parent = this; + return; + } + + // add the new child + _subDirectories.Add(child.Id, child); + _subDirectoriesByIndex.Add(child); + + // set the parent + child.Parent = this; + } + + public void AddChilds(IEnumerable childs) + { + foreach (var entry in childs) + AddChild(entry); + } + + public void RemoveChild(BaseFileEntry child) + { + RemoveChildById(child.Id); + } + + public void RemoveChildById(string childId) + { + // check for replace + if (_subDirectories.ContainsKey(childId)) + { + // get the old child + var oldChild = _subDirectories[childId]; + + // remove it + _subDirectories.Remove(childId); + _subDirectoriesByIndex.Remove(oldChild); + + // remove parent link + oldChild.Parent = null; + } + } + + public void ClearChilds() + { + _subDirectories.Clear(); + _subDirectoriesByIndex.Clear(); + } + + public nChildState HasChildrens + { + get + { + if (_subDirectories.Count != 0) + return nChildState.HasChilds; + if (!_subDirectoriesRefreshedInitially) + return nChildState.HasNotEvaluated; + return nChildState.HasNoChilds; + } + } + + private void RefreshResource() + { + // refresh the childs + _service.RefreshResource(_session, this); + + // set the state + _subDirectoriesRefreshedInitially = true; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntry.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntry.cs new file mode 100644 index 0000000000..8ad4b027ef --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntry.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects +{ + internal class BaseFileEntry : ICloudFileSystemEntry + { + protected string _id; + protected string _name; + protected ICloudDirectoryEntry _parent; + protected string _parentID; + protected IStorageProviderService _service; + protected IStorageProviderSession _session; + + private Dictionary _properties = new Dictionary(); + + internal bool IsDeleted { get; set; } + + public BaseFileEntry(string name, long length, DateTime modified, IStorageProviderService service, IStorageProviderSession session) + { + Name = name; + Length = length; + Modified = modified; + _service = new CachedServiceWrapper(service); //NOTE: Caching + _session = session; + + IsDeleted = false; + } + + #region ICloudFileSystemEntry Members + + public long Length { get; set; } + public DateTime Modified { get; set; } + + public string Name + { + get { return _name; } + set { _name = value; } + } + + public string Id + { + get { return !string.IsNullOrEmpty(_id) ? _id : _name; } + set { _id = value; } + } + + public string ParentID + { + get + { + if (!string.IsNullOrEmpty(_parentID)) + return _parentID; + if (_parent != null) + { + _parentID = _parent.Id; + return _parentID; + } + return null; + } + set { _parentID = value; } + } + + public ICloudDirectoryEntry Parent + { + get + { + if (_parent != null) + return _parent; + if (!string.IsNullOrEmpty(_parentID)) + { + _parent = (ICloudDirectoryEntry)_service.RequestResource(_session, _parentID, null); //get parent by ID + return _parent; + } + return null; + } + set + { + _parent = value; + if (_parent != null) + _parentID = _parent.Id; + } + } + + public string this[string property] + { + get { return GetPropertyValue(property); } + set { SetPropertyValue(property, value); } + } + + public string GetPropertyValue(string key) + { + object value; + if (_properties.TryGetValue(key, out value)) + { + return value.ToString(); + } + return string.Empty; + } + + public void SetPropertyValue(string key, object value) + { + if (_properties.ContainsKey(key)) + _properties.Remove(key); + + _properties.Add(key, value); + } + + public ICloudFileDataTransfer GetDataTransferAccessor() + { + return new BaseFileEntryDataTransfer(this, _service, _session); + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDataTransfer.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDataTransfer.cs new file mode 100644 index 0000000000..22cf510703 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDataTransfer.cs @@ -0,0 +1,163 @@ +using System; +using System.IO; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using System.Threading; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects +{ + internal class BaseFileEntryDataTransfer : ICloudFileDataTransfer + { + private readonly ICloudFileSystemEntry _fsEntry; + private readonly IStorageProviderService _service; + private readonly IStorageProviderSession _session; + + private class BaseFileEntryDataTransferAsyncContext + { + public object ProgressContext { get; set; } + public FileOperationProgressChanged ProgressCallback { get; set; } + } + + public BaseFileEntryDataTransfer(ICloudFileSystemEntry fileSystemEntry, IStorageProviderService service, IStorageProviderSession session) + { + _fsEntry = fileSystemEntry; + _session = session; + _service = service; + } + + #region ICloudFileDataTransfer Members + + public void Transfer(Stream targetDataStream, nTransferDirection direction) + { + Transfer(targetDataStream, direction, null, null); + } + + public void Transfer(Stream targetDataStream, nTransferDirection direction, FileOperationProgressChanged progressCallback, object progressContext) + { + if (direction == nTransferDirection.nUpload) + { + if (!CanTransfer(direction, targetDataStream.Length)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorLimitExceeded); + + _service.UploadResourceContent(_session, _fsEntry, targetDataStream, progressCallback, progressContext); + } + else + { + if (!CanTransfer(direction, _fsEntry.Length)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorLimitExceeded); + + _service.DownloadResourceContent(_session, _fsEntry, targetDataStream, progressCallback, progressContext); + } + } + + public void TransferAsyncProgress(Stream targetDataStream, nTransferDirection direction, FileOperationProgressChanged progressCallback, object progressContext) + { + var ctx = new BaseFileEntryDataTransferAsyncContext + { + ProgressCallback = progressCallback, + ProgressContext = progressContext + }; + + Transfer(targetDataStream, direction, FileOperationProgressChangedAsyncHandler, ctx); + } + + + public Stream GetDownloadStream() + { + return _service.CreateDownloadStream(_session, _fsEntry); + } + + public Stream GetUploadStream(long uploadSize) + { + return _service.CreateUploadStream(_session, _fsEntry, uploadSize); + } + + public IResumableUploadSession CreateResumableSession(long bytesToTransfer) + { + if (!CanTransfer(nTransferDirection.nUpload, bytesToTransfer, true)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorLimitExceeded); + + return _service.SupportsChunking ? _service.CreateUploadSession(_session, _fsEntry, bytesToTransfer) : null; + } + + public void AbortResumableSession(IResumableUploadSession transferSession) + { + _service.AbortUploadSession(_session, transferSession); + } + + public void Transfer(IResumableUploadSession transferSession, Stream data, long dataLength) + { + _service.UploadChunk(_session, transferSession, data, dataLength); + } + + void ICloudFileDataTransfer.Serialize(System.Runtime.Serialization.IFormatter dataFormatter, object objectGraph) + { + using (var cache = new MemoryStream()) + { + // serialize into the cache + dataFormatter.Serialize(cache, objectGraph); + + // go to start + cache.Position = 0; + + // transfer the cache + _fsEntry.GetDataTransferAccessor().Transfer(cache, nTransferDirection.nUpload); + } + } + + object ICloudFileDataTransfer.Deserialize(System.Runtime.Serialization.IFormatter dataFormatter) + { + using (var cache = new MemoryStream()) + { + // get the data + _fsEntry.GetDataTransferAccessor().Transfer(cache, nTransferDirection.nDownload); + + // go to the start + cache.Position = 0; + + // go ahead + return dataFormatter.Deserialize(cache); + } + } + + #endregion + + #region Internal callbacks + + private static void FileOperationProgressChangedAsyncHandler(object sender, FileDataTransferEventArgs e) + { + var ctx = e.CustomnContext as BaseFileEntryDataTransferAsyncContext; + + // define the thread + ThreadPool.QueueUserWorkItem(state => + { + // change the transferevent args + var eAsync = e.Clone() as FileDataTransferEventArgs; + ctx.ProgressCallback(sender, eAsync); + }); + } + + #endregion + + private bool CanTransfer(nTransferDirection direction, long bytes, bool useChunks = false) + { + var currentLimitss = _service.GetLimits(_session); + + long limit; + if (direction == nTransferDirection.nDownload) + { + limit = currentLimitss.MaxDownloadFileSize; + } + else if (!useChunks) + { + limit = currentLimitss.MaxUploadFileSize; + } + else + { + limit = currentLimitss.MaxChunkedUploadFileSize; + } + + return limit == -1 || limit >= bytes; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDownloadStream.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDownloadStream.cs new file mode 100644 index 0000000000..8d63f6405b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/BaseFileEntryDownloadStream.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects +{ + internal class BaseFileEntryDownloadStream : Stream, IDisposable + { + private Stream _baseStream; + private ICloudFileSystemEntry _fsEntry; + + public Stack _DisposableObjects = new Stack(); + + + public BaseFileEntryDownloadStream(Stream baseStream, ICloudFileSystemEntry fsEntry) + { + // save the information + _baseStream = baseStream; + _fsEntry = fsEntry; + } + + public override void Close() + { + // 1. stream close + _baseStream.Close(); + } + + public override bool CanRead + { + get { return _baseStream.CanRead; } + } + + public override bool CanSeek + { + get { return _baseStream.CanSeek; } + } + + public override bool CanWrite + { + get { return _baseStream.CanWrite; } + } + + public override void Flush() + { + _baseStream.Flush(); + } + + public override long Length + { + get { return _fsEntry.Length; } + } + + public override long Position + { + get { return _baseStream.Position; } + set { _baseStream.Position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _baseStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _baseStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _baseStream.SetLength(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + _baseStream.Write(buffer, offset, count); + } + + #region IDisposable Members + + void IDisposable.Dispose() + { + // dispose my basestream + _baseStream.Dispose(); + + // dispose my base calss + Dispose(); + + // dispose other objects + while (_DisposableObjects.Count > 0) + _DisposableObjects.Pop().Dispose(); + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/ResumableUploadSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/ResumableUploadSession.cs new file mode 100644 index 0000000000..c0662955c7 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BaseObjects/ResumableUploadSession.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects +{ + [Serializable] + public class ResumableUploadSession : IResumableUploadSession + { + private readonly Dictionary _items = new Dictionary(); + private readonly DateTime _createdOn = DateTime.UtcNow; + + public long BytesToTransfer { get; set; } + + public long BytesTransfered { get; set; } + + public ICloudFileSystemEntry File { get; set; } + + public string FileId { get; set; } + + public string FileName { get; set; } + + public string ParentId { get; set; } + + public ResumableUploadSessionStatus Status { get; set; } + + public DateTime CreatedOn + { + get { return _createdOn; } + } + + public object this[string key] + { + get { return GetItem(key); } + set { SetItem(key, value); } + } + + public ResumableUploadSession(ICloudFileSystemEntry file, long bytesToTransfer) + { + File = file; + BytesToTransfer = bytesToTransfer; + Status = ResumableUploadSessionStatus.None; + } + + public ResumableUploadSession(string fileId, string fileName, string parentId, long bytesToTransfer) + { + File = null; + BytesToTransfer = bytesToTransfer; + Status = ResumableUploadSessionStatus.None; + + FileId = fileId; + FileName = fileName; + ParentId = parentId; + } + + public void SetItem(string key, object value) + { + _items[key] = value; + } + + public object GetItem(string key) + { + return _items.ContainsKey(key) ? _items[key] : null; + } + + public T GetItem(string key) + { + var item = GetItem(key); + if (item is T) + { + return (T)item; + } + return default(T); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetConfiguration.cs new file mode 100644 index 0000000000..9f95231a89 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetConfiguration.cs @@ -0,0 +1,32 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet +{ + /// + /// The specific configuration for box.net + /// + public class BoxNetConfiguration : WebDavConfiguration + { + /// + /// ctor + /// + public BoxNetConfiguration() + : base(new Uri("https://dav.box.com/dav")) + { + } + + /// + /// This method returns a standard configuration for 1and1 + /// + /// + public static BoxNetConfiguration GetBoxNetConfiguration() + { + return new BoxNetConfiguration + { + Limits = new CloudStorageLimits(2L*1024L*1024L*1024L, -1), + TrustUnsecureSSLConnections = true + }; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetStorageProvider.cs new file mode 100644 index 0000000000..cb1ae1cd39 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/BoxNetStorageProvider.cs @@ -0,0 +1,13 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet +{ + internal class BoxNetStorageProvider : WebDavStorageProvider + { + public BoxNetStorageProvider() + : base(new BoxNetStorageProviderService()) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/Logic/BoxNetStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/Logic/BoxNetStorageProviderService.cs new file mode 100644 index 0000000000..c432b9c50a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/BoxNet/Logic/BoxNetStorageProviderService.cs @@ -0,0 +1,14 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.BoxNet.Logic +{ + internal class BoxNetStorageProviderService : WebDavStorageProviderService + { + protected override string OnNameBase(string targetUrl, IStorageProviderService service, IStorageProviderSession session, string nameBase) + { + return nameBase.StartsWith("https") ? nameBase : nameBase.Replace("http", "https"); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSConfiguration.cs new file mode 100644 index 0000000000..ff55a9608e --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSConfiguration.cs @@ -0,0 +1,50 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS +{ + /// + /// This class implements all BoxNet specific configurations + /// + public class CIFSConfiguration : ICloudStorageConfiguration + { + private bool _trustUnsecureSslConnections; + + /// + /// ctor of the Box.Net configuration + /// + public CIFSConfiguration(string path) + { + ServiceLocator = new Uri(path); + } + + /// + /// Specifies if we allow not secure ssl connections + /// + public bool TrustUnsecureSSLConnections + { + get { return _trustUnsecureSslConnections; } + set { _trustUnsecureSslConnections = value; } + } + + #region ICloudStorageConfiguration Members + + private CloudStorageLimits _limits = new CloudStorageLimits { MaxDownloadFileSize = -1, MaxUploadFileSize = -1 }; + + /// + /// Sets or gets the limits of a webdav configuration + /// + public CloudStorageLimits Limits + { + get { return _limits; } + + set { _limits = value; } + } + + /// + /// Gets the webdav service url + /// + public Uri ServiceLocator { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSStorageProvider.cs new file mode 100644 index 0000000000..d93809a101 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/CIFSStorageProvider.cs @@ -0,0 +1,12 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS +{ + internal class CIFSStorageProvider : GenericStorageProvider + { + public CIFSStorageProvider() + : base(new CachedServiceWrapper(new CIFSStorageProviderService())) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderService.cs new file mode 100644 index 0000000000..0bc6a07b9f --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderService.cs @@ -0,0 +1,292 @@ +using System; +using System.IO; +using System.Net; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS.Logic +{ + internal class CIFSStorageProviderService : GenericStorageProviderService + { + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return (token is ICredentials); + } + + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + // check if url available + if (!Directory.Exists(configuration.ServiceLocator.LocalPath)) + { + try + { + Directory.CreateDirectory(configuration.ServiceLocator.LocalPath); + } + catch (Exception) + { + return null; + } + } + + return new CIFSStorageProviderSession(token, configuration as CIFSConfiguration, this); + } + + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + // build path + string path; + + if (name.Equals("/")) + path = session.ServiceConfiguration.ServiceLocator.LocalPath; + else if (parent == null) + path = Path.Combine(session.ServiceConfiguration.ServiceLocator.LocalPath, name); + else + path = new Uri(GetResourceUrl(session, parent, name)).LocalPath; + + // check if file exists + if (File.Exists(path)) + { + // create the fileinfo + var fInfo = new FileInfo(path); + + var bf = new BaseFileEntry(fInfo.Name, fInfo.Length, fInfo.LastWriteTimeUtc, this, session) { Parent = parent }; + + // add to parent + if (parent != null) + (parent as BaseDirectoryEntry).AddChild(bf); + + // go ahead + return bf; + } + // check if directory exists + if (Directory.Exists(path)) + { + // build directory info + var dInfo = new DirectoryInfo(path); + + // build bas dir + var dir = CreateEntryByFileSystemInfo(dInfo, session) as BaseDirectoryEntry; + if (name.Equals("/")) + dir.Name = "/"; + + // add to parent + if (parent != null) + (parent as BaseDirectoryEntry).AddChild(dir); + + // refresh the childs + RefreshChildsOfDirectory(session, dir); + + // go ahead + return dir; + } + + return null; + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + // nothing to do for files + if (!(resource is ICloudDirectoryEntry)) + return; + + // Refresh schild + RefreshChildsOfDirectory(session, resource as BaseDirectoryEntry); + } + + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + // generate the loca path + var uriPath = GetResourceUrl(session, entry, null); + var uri = new Uri(uriPath); + + // removed the file + if (File.Exists(uri.LocalPath)) + File.Delete(uri.LocalPath); + else if (Directory.Exists(uri.LocalPath)) + Directory.Delete(uri.LocalPath, true); + + // go ahead + return true; + + } + + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + // build the new uri + var newPlace = GetResourceUrl(session, newParent, fsentry.Name); + + if (RenameResourceEx(session, fsentry, newPlace)) + { + // remove from parent + (fsentry.Parent as BaseDirectoryEntry).RemoveChild(fsentry as BaseFileEntry); + + // add to new parent + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + + return true; + } + + return false; + } + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + // get the full path + var uriPath = GetResourceUrl(session, fileSystemEntry, null); + var uri = new Uri(uriPath); + + // open src file + return new FileStream(uri.LocalPath, FileMode.Open); + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + // get the full path + var uriPath = GetResourceUrl(session, fileSystemEntry, null); + var uri = new Uri(uriPath); + + // set the new size + var f = fileSystemEntry as BaseFileEntry; + f.Length = uploadSize; + + // create the file if not exists + FileStream fs; + if (!File.Exists(uri.LocalPath)) + fs = File.Create(uri.LocalPath); + else + fs = File.OpenWrite(uri.LocalPath); + + // go ahead + return fs; + } + + public override bool SupportsDirectRetrieve + { + get { return false; } + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + } + + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + // build the full url + var resFull = GetResourceUrl(session, parent, name); + var uri = new Uri(resFull); + + // create the director + var dinfo = Directory.CreateDirectory(uri.LocalPath); + + // create the filesystem object + ICloudFileSystemEntry fsEntry = CreateEntryByFileSystemInfo(dinfo, session); + + // add parent child + if (parent != null) + (parent as BaseDirectoryEntry).AddChild(fsEntry as BaseFileEntry); + + // go ahead + return fsEntry; + } + + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + // get new name uri + var uriPath = GetResourceUrl(session, fsentry.Parent, newName); + + // do it + return RenameResourceEx(session, fsentry, uriPath); + } + + + #region Helper + + private BaseFileEntry CreateEntryByFileSystemInfo(FileSystemInfo info, IStorageProviderSession session) + { + if (info is DirectoryInfo) + return new BaseDirectoryEntry(info.Name, 0, info.LastWriteTimeUtc, this, session); + if (info is FileInfo) + return new BaseFileEntry(info.Name, (info as FileInfo).Length, info.LastWriteTimeUtc, this, session); + throw new Exception("Invalid filesysteminfo type"); + } + + private void RefreshChildsOfDirectory(IStorageProviderSession session, BaseDirectoryEntry dir) + { + // get the location + var reslocation = GetResourceUrl(session, dir, null); + + // ensure that we have a trailing slash + reslocation = reslocation.TrimEnd('/'); + reslocation = reslocation + "/"; + + // build the uri + var resUri = new Uri(reslocation); + + // convert BaseDir to DirInfo + var dInfo = new DirectoryInfo(resUri.LocalPath); + + // clear childs + dir.ClearChilds(); + + // get all childs + foreach (var fInfo in dInfo.GetFileSystemInfos()) + { + var f = CreateEntryByFileSystemInfo(fInfo, session); + dir.AddChild(f); + } + } + + public bool RenameResourceEx(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newFullPath) + { + // get the uri + var uriPath = GetResourceUrl(session, fsentry, null); + var srUri = new Uri(uriPath); + + // get new name uri + var tgUri = new Uri(newFullPath); + + // rename + FileSystemInfo f; + if (File.Exists(srUri.LocalPath)) + { + f = new FileInfo(srUri.LocalPath); + ((FileInfo)f).MoveTo(tgUri.LocalPath); + } + else if (Directory.Exists(srUri.LocalPath)) + { + f = new DirectoryInfo(srUri.LocalPath); + ((DirectoryInfo)f).MoveTo(tgUri.LocalPath); + } + else + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + } + + // reload file info + if (File.Exists(tgUri.LocalPath)) + { + f = new FileInfo(tgUri.LocalPath); + } + else if (Directory.Exists(tgUri.LocalPath)) + { + f = new DirectoryInfo(tgUri.LocalPath); + } + else + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + } + + // update fsEntry + var fs = fsentry as BaseFileEntry; + fs.Name = Path.GetFileName(tgUri.LocalPath); + fs.Length = (f is FileInfo ? (f as FileInfo).Length : 0); + fs.Modified = f.LastWriteTimeUtc; + + // go ahead + return true; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderSession.cs new file mode 100644 index 0000000000..a24a2d8067 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CIFS/Logic/CIFSStorageProviderSession.cs @@ -0,0 +1,24 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.CIFS.Logic +{ + internal class CIFSStorageProviderSession : IStorageProviderSession + { + public CIFSStorageProviderSession(ICloudStorageAccessToken token, CIFSConfiguration config, IStorageProviderService service) + { + SessionToken = token; + ServiceConfiguration = config; + Service = service; + } + + #region IStorageProviderSession Members + + public ICloudStorageAccessToken SessionToken { get; private set; } + + public IStorageProviderService Service { get; private set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CachedServiceWrapper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CachedServiceWrapper.cs new file mode 100644 index 0000000000..195dcfc037 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/CachedServiceWrapper.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.IO; +using AppLimit.CloudComputing.SharpBox.Common.Cache; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider +{ + public class CachedServiceWrapper : IStorageProviderService + { + private static readonly CachedDictionary FsCache = + new CachedDictionary("sbox-fs", TimeSpan.FromSeconds(120), TimeSpan.Zero, x => x != null); + + private readonly IStorageProviderService _service; + + public CachedServiceWrapper(IStorageProviderService service) + { + if (service == null) + throw new ArgumentNullException("service"); + + _service = service; + } + + public bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return _service.VerifyAccessTokenType(token); + } + + public IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + return _service.CreateSession(token, configuration); + } + + public void CloseSession(IStorageProviderSession session) + { + FsCache.Reset(GetSessionKey(session), string.Empty); + _service.CloseSession(session); + } + + public CloudStorageLimits GetLimits(IStorageProviderSession session) + { + return _service.GetLimits(session); + } + + public ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + return FsCache.Get(GetSessionKey(session), GetCacheKey(session, name, parent), () => _service.RequestResource(session, name, parent)); + } + + private static string GetSessionKey(IStorageProviderSession session) + { + return session.GetType().Name + " " + session.SessionToken; + } + + private string GetCacheKey(IStorageProviderSession session, string nameOrId, ICloudFileSystemEntry parent) + { + return GetResourceUrl(session, parent, nameOrId); + } + + + public void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + var cached = FsCache.Get(GetSessionKey(session), GetCacheKey(session, null, resource), null) as ICloudDirectoryEntry; + + if (cached == null || cached.HasChildrens == nChildState.HasNotEvaluated) + { + _service.RefreshResource(session, resource); + FsCache.Add(GetSessionKey(session), GetCacheKey(session, null, resource), resource); + } + } + + public ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + return _service.CreateResource(session, name, parent); + } + + public bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + FsCache.Reset(GetSessionKey(session), string.Empty); + return _service.DeleteResource(session, entry); + } + + public bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + FsCache.Reset(GetSessionKey(session), string.Empty); + return _service.MoveResource(session, fsentry, newParent); + } + + public bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + FsCache.Reset(GetSessionKey(session), string.Empty); + return _service.CopyResource(session, fsentry, newParent); + } + + public bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + FsCache.Reset(GetSessionKey(session), string.Empty); + return _service.RenameResource(session, fsentry, newName); + } + + public void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token) + { + _service.StoreToken(session, tokendata, token); + } + + public ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + return _service.LoadToken(tokendata); + } + + public string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, string additionalPath) + { + return _service.GetResourceUrl(session, fileSystemEntry, additionalPath); + } + + public void DownloadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext) + { + _service.DownloadResourceContent(session, fileSystemEntry, targetDataStream, progressCallback, progressContext); + } + + public Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + return _service.CreateDownloadStream(session, fileSystemEntry); + } + + public void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + _service.CommitStreamOperation(session, fileSystemEntry, direction, notDisposedStream); + } + + public void UploadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext) + { + _service.UploadResourceContent(session, fileSystemEntry, targetDataStream, progressCallback, progressContext); + } + + public Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + return _service.CreateUploadStream(session, fileSystemEntry, uploadSize); + } + + public bool SupportsDirectRetrieve + { + get { return _service.SupportsDirectRetrieve; } + } + + + public bool SupportsChunking + { + get { return _service.SupportsChunking; } + } + + public IResumableUploadSession CreateUploadSession(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long bytesToTransfer) + { + return _service.CreateUploadSession(session, fileSystemEntry, bytesToTransfer); + } + + public void AbortUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + _service.AbortUploadSession(session, uploadSession); + } + + public void UploadChunk(IStorageProviderSession session, IResumableUploadSession uploadSession, Stream stream, long chunkLength) + { + _service.UploadChunk(session, uploadSession, stream, chunkLength); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxAccountInfo.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxAccountInfo.cs new file mode 100644 index 0000000000..c9d6e008b9 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxAccountInfo.cs @@ -0,0 +1,60 @@ +using System; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /* + * { + * “country”: “”, + * “display_name”: “John Q. User”, + * “quota_info”: + * { + * “shared”: 37378890, + * “quota”: 62277025792, + * “normal”: 263758550 + * }, + * “uid”: “174” + * } + */ + + /// + /// This class contains information about the dropbox account + /// + public class DropBoxAccountInfo + { + /// + /// The country where the user comes from + /// + public readonly string Country; + + /// + /// The displayname of the user + /// + public readonly string DisplayName; + + /// + /// The user Id + /// + public readonly int UserId; + + /// + /// Quotainformation of dropbox + /// + public readonly DropBoxQuotaInfo QuotaInfo; + + internal DropBoxAccountInfo(string jmstext) + { + var jh = new JsonHelper(); + if (!jh.ParseJsonMessage(jmstext)) + return; + + Country = jh.GetProperty("country"); + DisplayName = jh.GetProperty("display_name"); + UserId = jh.GetPropertyInt("uid"); + + var quotainfo = jh.GetSubObjectString("quota_info"); + if (quotainfo != null) + QuotaInfo = new DropBoxQuotaInfo(quotainfo); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxBaseTokenInformation.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxBaseTokenInformation.cs new file mode 100644 index 0000000000..47faf419f2 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxBaseTokenInformation.cs @@ -0,0 +1,22 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /// + /// The base class of all credentials + /// + public class DropBoxBaseTokenInformation + { + /// + /// ConsumerKey of the DropBox application, provided by the + /// DropBox-Developer-Portal + /// + public string ConsumerKey { get; set; } + + /// + /// ConsumerSecret of the DropBox application, provided by the + /// DropBox-Developer-Portal + /// + public string ConsumerSecret { get; set; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxConfiguration.cs new file mode 100644 index 0000000000..99d2538188 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxConfiguration.cs @@ -0,0 +1,124 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /// + /// This enum defines possible API versions DropBox offers to + /// their customers + /// + public enum DropBoxAPIVersion + { + /// + /// Version 0 of the DropBox API + /// + V0 = 0, + + /// + /// Version 1 of the DropBox API + /// + V1 = 1, + + /// + /// The current stable version which will be used by SharpBox by default + /// + Stable = 1 + }; + + /// + /// DropBoxConfiguration conains the default access information for the DropBox + /// storage and synchronization services. This class implements from the + /// ICloudStorageConfiguration interface and can be used with an instance of CloudStorage + /// + public class DropBoxConfiguration : ICloudStorageConfiguration + { + /// + /// This method creates and returns the url which has to be used to get a access token + /// during the OAuth based authorization process + /// + public Uri RequestTokenUrl + { + get { return new Uri(DropBoxStorageProviderService.GetUrlString(DropBoxStorageProviderService.DropBoxOAuthRequestToken, this)); } + } + + /// + /// This method creates and returns the url which has to be used to get a access token + /// during the OAuth based authorization process + /// + public Uri AccessTokenUrl + { + get { return new Uri(DropBoxStorageProviderService.GetUrlString(DropBoxStorageProviderService.DropBoxOAuthAccessToken, this)); } + } + + /// + /// This method creates and returns the url which can be used in the browser + /// to authorize the end user + /// + public Uri AuthorizationTokenUrl + { + get { return new Uri(DropBoxStorageProviderService.GetUrlString(DropBoxStorageProviderService.DropBoxOAuthAuthToken, null)); } + } + + /// + /// This field contains the callback URL which will be used in the oAuth + /// request. Default will be sharpbox.codeplex.com + /// + public Uri AuthorizationCallBack = new Uri("http://sharpox.codeplex.com"); + + /// + /// The APIVersion which will be used for communication with dropbox. As default + /// the stable version is set! + /// + public DropBoxAPIVersion APIVersion { get; set; } + + /// + /// Constructor of a dropbox configuration + /// + public DropBoxConfiguration() + : this(new Uri(DropBoxStorageProviderService.DropBoxBaseUrl)) + { + APIVersion = DropBoxAPIVersion.Stable; + } + + /// + /// Allows to create the dopbox configuration with a special + /// service provider location + /// + /// + public DropBoxConfiguration(Uri serviceLocator) + { + ServiceLocator = serviceLocator; + } + + /// + /// This method generates an instance of the default dropbox configuration + /// + /// Instance of the DropBoxConfiguration-Class with default settings + public static DropBoxConfiguration GetStandardConfiguration() + { + return new DropBoxConfiguration(); + } + + /// + /// If true this value indicates the all ssl connection are valid. This means also ssl connection + /// with an invalid certificate will be accepted. + /// + public bool TrustUnsecureSSLConnections + { + get { return false; } + } + + /// + /// The limits of dropbox + /// + public CloudStorageLimits Limits + { + get { return new CloudStorageLimits(150*1024*1024, -1) { MaxChunkedUploadFileSize = -1 }; } + } + + /// + /// Gets the currently used dropbox url + /// + public Uri ServiceLocator { get; private set; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxQuotaInfo.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxQuotaInfo.cs new file mode 100644 index 0000000000..1752746f9b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxQuotaInfo.cs @@ -0,0 +1,45 @@ +using System; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /* + * { + * “shared”: 37378890, + * “quota”: 62277025792, + * “normal”: 263758550 + * } + */ + + /// + /// This class contains information about the dropbox quota + /// + public class DropBoxQuotaInfo + { + /// + /// How many bytes are shared with other users + /// + public readonly ulong SharedBytes; + + /// + /// What is the size limit of the dropbox + /// + public readonly ulong QuotaBytes; + + /// + /// How many not shared bytes are used + /// + public readonly ulong NormalBytes; + + internal DropBoxQuotaInfo(string jmstext) + { + var jh = new JsonHelper(); + if (jh.ParseJsonMessage(jmstext)) + { + SharedBytes = Convert.ToUInt64(jh.GetProperty("shared")); + QuotaBytes = Convert.ToUInt64(jh.GetProperty("quota")); + NormalBytes = Convert.ToUInt64(jh.GetProperty("normal")); + } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxRequestToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxRequestToken.cs new file mode 100644 index 0000000000..b9da58fdf0 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxRequestToken.cs @@ -0,0 +1,29 @@ +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /// + /// This token will be issued during the web based token generation + /// process for dropbox + /// + public class DropBoxRequestToken : ICloudStorageAccessToken + { + internal OAuthToken RealToken; + + internal DropBoxRequestToken(OAuthToken realToken) + { + RealToken = realToken; + } + + public override string ToString() + { + return RealToken.TokenKey + "&" + RealToken.TokenSecret; + } + + public static DropBoxRequestToken Parse(string token) + { + var splited = token.Split('&'); + return new DropBoxRequestToken(new OAuthToken(splited[0], splited[1])); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxResourceIDHelpers.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxResourceIDHelpers.cs new file mode 100644 index 0000000000..fa74dc30e1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxResourceIDHelpers.cs @@ -0,0 +1,32 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + internal static class DropBoxResourceIDHelpers + { + public static string GetResourcePath(ICloudFileSystemEntry resource) + { + return GetResourcePath(resource, null); + } + + public static string GetResourcePath(ICloudFileSystemEntry parent, string nameOrId, string parentId = null) + { + nameOrId = !string.IsNullOrEmpty(nameOrId) ? nameOrId.Trim('/') : string.Empty; + if (parent != null) + parentId = parent.Id; + parentId = (parentId ?? "").Trim('/'); + if (string.IsNullOrEmpty(parentId)) + return nameOrId; + if (string.IsNullOrEmpty(nameOrId)) + return parentId; + return parentId + "/" + nameOrId; + } + + public static string GetParentID(string path) + { + path = path.Trim('/'); + int index = path.LastIndexOf('/'); + return index != -1 ? path.Substring(0, index) : "/"; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProvider.cs new file mode 100644 index 0000000000..2cb05632f0 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProvider.cs @@ -0,0 +1,40 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + internal class DropBoxStorageProvider : GenericStorageProvider + { + public DropBoxStorageProvider() + : base(new CachedServiceWrapper(new DropBoxStorageProviderService())) + { + } + + public override Uri GetFileSystemObjectUrl(string path, ICloudDirectoryEntry parent) + { + // get the filesystem + var entry = GetFileSystemObject(path, parent); + + // get the download url + var url = DropBoxStorageProviderService.GetDownloadFileUrlInternal(Session, entry); + + // get the right session + var session = (DropBoxStorageProviderSession)Session; + + // generate the oauth url + var svc = new OAuthService(); + url = svc.GetProtectedResourceUrl(url, session.Context, session.SessionToken as DropBoxToken, null, WebRequestMethodsEx.Http.Get); + + // go ahead + return new Uri(url); + } + + public override string GetFileSystemObjectPath(ICloudFileSystemEntry fsObject) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(fsObject); + return "/" + path; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProviderTools.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProviderTools.cs new file mode 100644 index 0000000000..362003887c --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxStorageProviderTools.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; + +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + /// + /// This class contains a couple a tools which will be helpful + /// when working with dropbox only + /// + public static class DropBoxStorageProviderTools + { + private const string DropBoxMobileLogin = DropBoxStorageProviderService.DropBoxBaseUrl + "/0/token"; + + /// + /// This method retrieves a new request token from the dropbox server + /// + /// + /// + /// + /// + public static DropBoxRequestToken GetDropBoxRequestToken(DropBoxConfiguration configuration, string consumerKey, string consumerSecret) + { + // build the consumer context + var consumerContext = new OAuthConsumerContext(consumerKey, consumerSecret); + + // build up the oauth session + var serviceContext = new OAuthServiceContext(configuration.RequestTokenUrl.ToString(), + configuration.AuthorizationTokenUrl.ToString(), configuration.AuthorizationCallBack.ToString(), + configuration.AccessTokenUrl.ToString()); + + // get a request token from the provider + var svc = new OAuthService(); + var oauthToken = svc.GetRequestToken(serviceContext, consumerContext); + return oauthToken != null ? new DropBoxRequestToken(oauthToken) : null; + } + + /// + /// This method builds derived from the request token a valid authorization url which can be used + /// for web applications + /// + /// + /// + /// + public static string GetDropBoxAuthorizationUrl(DropBoxConfiguration configuration, DropBoxRequestToken dropBoxRequestToken) + { + // build the auth url + return OAuthUrlGenerator.GenerateAuthorizationUrl(configuration.AuthorizationTokenUrl.ToString(), + configuration.AuthorizationCallBack.ToString(), + dropBoxRequestToken.RealToken); + } + + /// + /// This method is able to exchange the request token into an access token which can be used in + /// sharpbox. It is necessary that the user validated the request via authorization url otherwise + /// this call wil results in an unauthorized exception! + /// + /// + /// + /// + /// + /// + public static ICloudStorageAccessToken ExchangeDropBoxRequestTokenIntoAccessToken(DropBoxConfiguration configuration, string consumerKey, string ConsumerSecret, DropBoxRequestToken dropBoxRequestToken) + { + // build the consumer context + var consumerContext = new OAuthConsumerContext(consumerKey, ConsumerSecret); + + // build up the oauth session + var serviceContext = new OAuthServiceContext(configuration.RequestTokenUrl.ToString(), + configuration.AuthorizationTokenUrl.ToString(), configuration.AuthorizationCallBack.ToString(), + configuration.AccessTokenUrl.ToString()); + + // build the access token + var svc = new OAuthService(); + var accessToken = svc.GetAccessToken(serviceContext, consumerContext, dropBoxRequestToken.RealToken); + if (accessToken == null) + throw new UnauthorizedAccessException(); + + // create the access token + return new DropBoxToken(accessToken, + new DropBoxBaseTokenInformation + { + ConsumerKey = consumerKey, + ConsumerSecret = ConsumerSecret + }); + } + + /// + /// This method returns the account information of a dropbox account + /// + /// + /// + public static DropBoxAccountInfo GetAccountInformation(ICloudStorageAccessToken token) + { + // generate the dropbox service + var service = new DropBoxStorageProviderService(); + + // generate a session + var session = service.CreateSession(token, DropBoxConfiguration.GetStandardConfiguration()); + if (session == null) + return null; + + // receive acc info + var accInfo = service.GetAccountInfo(session); + + // close the session + service.CloseSession(session); + + // go ahead + return accInfo; + } + + /// + /// This method returns the public URL of a DropBox file or folder + /// + /// + /// + /// + public static Uri GetPublicObjectUrl(ICloudStorageAccessToken token, ICloudFileSystemEntry fsEntry) + { + // check parameters + if (fsEntry == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get the resource path + var resourcePath = GenericHelper.GetResourcePath(fsEntry); + + // check if it is a public dir + if (!resourcePath.ToLower().Contains("/public/")) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters); + + // get accoutn inf + var accInfo = GetAccountInformation(token); + + // http;//dl.dropbox.com/u/" + userid / + folder + filename + var uri = "http://dl.dropbox.com/u/" + accInfo.UserId.ToString() + resourcePath.Replace("/Public", ""); + + // go ahead + return new Uri(uri); + } + + /// + /// This method offers the mobile login api of dropbox for users who are migrating from version 0 of the + /// dropbox API because version 1 supports token based logins only + /// + /// + /// + /// + /// + /// + public static ICloudStorageAccessToken LoginWithMobileAPI(string username, string password, string appkey, string appsecret) + { + // get the configuration + var configuration = DropBoxConfiguration.GetStandardConfiguration(); + + // build the consumer context + var consumerContext = new OAuthConsumerContext(appkey, appsecret); + + // build up the oauth session + var serviceContext = new OAuthServiceContext(configuration.RequestTokenUrl.ToString(), + configuration.AuthorizationTokenUrl.ToString(), configuration.AuthorizationCallBack.ToString(), + configuration.AccessTokenUrl.ToString()); + + // get a request token from the provider + var svc = new OAuthService(); + var oAuthRequestToken = svc.GetRequestToken(serviceContext, consumerContext); + if (oAuthRequestToken == null) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidConsumerKeySecret); + } + var dropBoxRequestToken = new DropBoxToken(oAuthRequestToken, new DropBoxBaseTokenInformation { ConsumerKey = appkey, ConsumerSecret = appsecret }); + + // generate the dropbox service + var service = new DropBoxStorageProviderService(); + + // build up a request Token Session + var requestSession = new DropBoxStorageProviderSession(dropBoxRequestToken, configuration, consumerContext, service); + + // build up the parameters + var param = new Dictionary + { + { "email", username }, + { "password", password } + }; + + // call the mobile login api + string result; + + try + { + int code; + result = DropBoxRequestParser.RequestResourceByUrl(DropBoxMobileLogin, param, service, requestSession, out code); + if (result.Length == 0) + throw new UnauthorizedAccessException(); + } + catch (Exception netex) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotContactStorageService, netex); + } + + // exchange a request token for an access token + var accessToken = new DropBoxToken(result); + + // adjust the token + if (accessToken.BaseTokenInformation == null) + { + accessToken.BaseTokenInformation = new DropBoxBaseTokenInformation + { + ConsumerKey = appkey, + ConsumerSecret = appsecret + }; + } + + // go ahead + return accessToken; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxToken.cs new file mode 100644 index 0000000000..328dec8124 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/DropBoxToken.cs @@ -0,0 +1,44 @@ +using System; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox +{ + internal class DropBoxToken : OAuthToken, ICloudStorageAccessToken + { + public DropBoxBaseTokenInformation BaseTokenInformation; + + public DropBoxToken(string jsonString) + : base("", "") + { + var jh = new JsonHelper(); + if (jh.ParseJsonMessage(jsonString)) + { + TokenSecret = jh.GetProperty("secret"); + TokenKey = jh.GetProperty("token"); + } + } + + public DropBoxToken(OAuthToken token, DropBoxBaseTokenInformation baseCreds) + : base(token.TokenKey, token.TokenSecret) + { + BaseTokenInformation = baseCreds; + } + + public DropBoxToken(string tokenKey, string tokenSecret, DropBoxBaseTokenInformation baseCreds) + : base(tokenKey, tokenSecret) + { + BaseTokenInformation = baseCreds; + } + + public ICloudStorageConfiguration ServiceConfiguration + { + get { return DropBoxConfiguration.GetStandardConfiguration(); } + } + + public override string ToString() + { + return string.Format("{0}+{1}", TokenKey, TokenSecret); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxRequestParser.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxRequestParser.cs new file mode 100644 index 0000000000..90754d95dd --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxRequestParser.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; + +using AppLimit.CloudComputing.SharpBox.Common.Cache; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic +{ + internal class DropBoxRequestParser + { + public static string RequestResourceByUrl(string url, IStorageProviderService service, IStorageProviderSession session, out int netErrorCode) + { + return RequestResourceByUrl(url, null, service, session, out netErrorCode); + } + + private static readonly CachedDictionary> SessionHashStorage + = new CachedDictionary>("dropbox-requests-hash", TimeSpan.Zero, TimeSpan.FromMinutes(30), x => true); + + public static void Addhash(string url, string hash, string response, IStorageProviderSession session) + { + SessionHashStorage.Add(session.SessionToken.ToString(), url, new KeyValuePair(hash, response)); + } + + public static string RequestResourceByUrl(string url, Dictionary parameters, IStorageProviderService service, IStorageProviderSession session, out int netErrorCode) + { + // cast the dropbox session + var dropBoxSession = session as DropBoxStorageProviderSession; + + // instance the oAuthServer + var svc = new OAuthService(); + + var urlhash = new KeyValuePair(); + if (!string.IsNullOrEmpty(url) && url.Contains("/metadata/")) + { + //Add the hash attr if any + urlhash = SessionHashStorage.Get(session.SessionToken.ToString(), url, () => new KeyValuePair()); + } + + if (!string.IsNullOrEmpty(urlhash.Key) && !string.IsNullOrEmpty(urlhash.Value)) + { + //Add params + if (parameters == null) + parameters = new Dictionary(); + parameters.Add("hash", urlhash.Key); + } + + // build the webrequest to protected resource + var request = svc.CreateWebRequest(url, WebRequestMethodsEx.Http.Get, null, null, dropBoxSession.Context, (DropBoxToken)dropBoxSession.SessionToken, parameters); + + // get the error code + WebException ex; + + // perform a simple webrequest + using (Stream s = svc.PerformWebRequest(request, null, out netErrorCode, out ex, + code => !string.IsNullOrEmpty(urlhash.Key) && !string.IsNullOrEmpty(urlhash.Value) && code == 304) /*to check code without downloading*/) + { + if (!string.IsNullOrEmpty(urlhash.Key) && !string.IsNullOrEmpty(urlhash.Value) && netErrorCode == 304) + { + return urlhash.Value; + } + if (s == null) + return ""; + + // read the memory stream and convert to string + using (var response = new StreamReader(s)) + { + return response.ReadToEnd(); + } + } + } + + public static BaseFileEntry CreateObjectsFromJsonString(string jsonMessage, IStorageProviderService service, IStorageProviderSession session) + { + return UpdateObjectFromJsonString(jsonMessage, null, service, session); + } + + public static BaseFileEntry UpdateObjectFromJsonString(string jsonMessage, BaseFileEntry objectToUpdate, IStorageProviderService service, IStorageProviderSession session) + { + // verify if we have a directory or a file + var jc = new JsonHelper(); + if (!jc.ParseJsonMessage(jsonMessage)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + + var isDir = jc.GetBooleanProperty("is_dir"); + + // create the entry + BaseFileEntry dbentry; + bool bEntryOk; + + if (isDir) + { + if (objectToUpdate == null) + dbentry = new BaseDirectoryEntry("Name", 0, DateTime.Now, service, session); + else + dbentry = objectToUpdate as BaseDirectoryEntry; + + bEntryOk = BuildDirectyEntry(dbentry as BaseDirectoryEntry, jc, service, session); + } + else + { + if (objectToUpdate == null) + dbentry = new BaseFileEntry("Name", 0, DateTime.Now, service, session); + else + dbentry = objectToUpdate; + + bEntryOk = BuildFileEntry(dbentry, jc); + } + + // parse the childs and fill the entry as self + if (!bEntryOk) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotContactStorageService); + + // set the is deleted flag + try + { + // try to read the is_deleted property + dbentry.IsDeleted = jc.GetBooleanProperty("is_deleted"); + } + catch (Exception) + { + // the is_deleted proprty is missing (so it's not a deleted file or folder) + dbentry.IsDeleted = false; + } + + // return the child + return dbentry; + } + + private static bool BuildFileEntry(BaseFileEntry fileEntry, JsonHelper jh) + { + /* + * "revision": 29251, + "thumb_exists": false, + "bytes": 37941660, + "modified": "Tue, 01 Jun 2010 14:45:09 +0000", + "path": "/Public/2010_06_01 15_53_48_336.nvl", + "is_dir": false, + "icon": "page_white", + "mime_type": "application/octet-stream", + "size": "36.2MB" + * */ + + // set the size + fileEntry.Length = Convert.ToInt64(jh.GetProperty("bytes")); + + // set the modified time + fileEntry.Modified = jh.GetDateTimeProperty("modified"); + + // build the displayname + var DropBoxPath = jh.GetProperty("path"); + var arr = DropBoxPath.Split('/'); + fileEntry.Name = arr.Length > 0 ? arr[arr.Length - 1] : DropBoxPath; + + if (DropBoxPath.Equals("/")) + { + fileEntry.Id = "/"; + fileEntry.ParentID = null; + } + else + { + fileEntry.Id = DropBoxPath.Trim('/'); + fileEntry.ParentID = DropBoxResourceIDHelpers.GetParentID(DropBoxPath); + } + + + // set the hash property if possible + var hashValue = jh.GetProperty("hash"); + if (hashValue.Length > 0) + fileEntry.SetPropertyValue("hash", hashValue); + + // set the path property + fileEntry.SetPropertyValue("path", DropBoxPath.Equals("/") ? "" : DropBoxPath); + + // set the revision value if possible + var revValue = jh.GetProperty("rev"); + if (revValue.Length > 0) + { + fileEntry.SetPropertyValue("rev", revValue); + } + + // go ahead + return true; + } + + private static bool BuildDirectyEntry(BaseDirectoryEntry dirEntry, JsonHelper jh, IStorageProviderService service, IStorageProviderSession session) + { + // build the file entry part + if (!BuildFileEntry(dirEntry, jh)) + return false; + + // now take the content + var content = jh.GetListProperty("contents"); + + if (content.Count == 0) + return true; + + // remove all childs + dirEntry.ClearChilds(); + + // add the childs + foreach (var jsonContent in content) + { + // parse the item + var jc = new JsonHelper(); + if (!jc.ParseJsonMessage(jsonContent)) + continue; + + // check if we have a directory + var isDir = jc.GetBooleanProperty("is_dir"); + + BaseFileEntry fentry; + + if (isDir) + { + fentry = new BaseDirectoryEntry("Name", 0, DateTime.Now, service, session); + } + else + { + fentry = new BaseFileEntry("Name", 0, DateTime.Now, service, session); + } + + // build the file attributes + BuildFileEntry(fentry, jc); + + // establish parent child realtionship + dirEntry.AddChild(fentry); + } + + // set the length + dirEntry.Length = dirEntry.Count; + + // go ahead + return true; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderService.cs new file mode 100644 index 0000000000..ce5ac871d8 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderService.cs @@ -0,0 +1,721 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Web; +using AppLimit.CloudComputing.SharpBox.Common.Extensions; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Common.Net; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic +{ + internal class DropBoxStorageProviderService : GenericStorageProviderService + { + // token storage definitions + public const string TokenDropBoxCredUsername = "TokenDropBoxUsername"; + public const string TokenDropBoxCredPassword = "TokenDropBoxPassword"; + public const string TokenDropBoxAppKey = "TokenDropBoxAppKey"; + public const string TokenDropBoxAppSecret = "TokenDropBoxAppSecret"; + + // server and base url + public const string DropBoxPrototcolPrefix = "https://"; + public const string DropBoxServer = "api.dropbox.com"; + public const string DropBoxEndUserServer = "www.dropbox.com"; + public const string DropBoxContentServer = "api-content.dropbox.com"; + public const string DropBoxBaseUrl = DropBoxPrototcolPrefix + DropBoxServer; + public const string DropBoxBaseUrlEndUser = DropBoxPrototcolPrefix + DropBoxEndUserServer; + + // api version + public const string DropBoxApiVersion = "{0}"; // it's a formt placeholder + + // action urls + public const string DropBoxGetAccountInfo = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/account/info"; + public const string DropBoxSandboxRoot = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/metadata/sandbox/"; + public const string DropBoxDropBoxRoot = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/metadata/dropbox/"; + public const string DropBoxCreateFolder = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/fileops/create_folder"; + public const string DropBoxDeleteItem = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/fileops/delete"; + public const string DropBoxMoveItem = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/fileops/move"; + public const string DropBoxCopyItem = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/fileops/copy"; + + public const string DropBoxChunkedUpload = DropBoxPrototcolPrefix + DropBoxContentServer + "/" + DropBoxApiVersion + "/chunked_upload"; + public const string DropBoxCommitChunkedUpload = DropBoxPrototcolPrefix + DropBoxContentServer + "/" + DropBoxApiVersion + "/commit_chunked_upload"; + + public const string DropBoxUploadDownloadFile = DropBoxPrototcolPrefix + DropBoxContentServer + "/" + DropBoxApiVersion + "/files"; + + // authorization urls + public const string DropBoxOAuthRequestToken = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/oauth/request_token"; + public const string DropBoxOAuthAccessToken = DropBoxBaseUrl + "/" + DropBoxApiVersion + "/oauth/access_token"; + public const string DropBoxOAuthAuthToken = DropBoxBaseUrlEndUser + "/" + DropBoxApiVersion + "/oauth/authorize"; + + #region DropBox Specific members + + public DropBoxAccountInfo GetAccountInfo(IStorageProviderSession session) + { + // request the json object via oauth + int code; + var res = DropBoxRequestParser.RequestResourceByUrl(GetUrlString(DropBoxGetAccountInfo, session.ServiceConfiguration), this, session, out code); + + // parse the jason stuff + return new DropBoxAccountInfo(res); + } + + #endregion + + #region IStorageProviderService Members + + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return (token is DropBoxToken); + } + + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + // get the user credentials + var userToken = token as DropBoxToken; + var svcConfig = configuration as DropBoxConfiguration; + + // get the session + return Authorize(userToken, svcConfig); + } + + public override CloudStorageLimits GetLimits(IStorageProviderSession session) + { + var accountInfo = GetAccountInfo(session); + var quotaRemained = accountInfo.QuotaInfo.QuotaBytes - accountInfo.QuotaInfo.NormalBytes - accountInfo.QuotaInfo.SharedBytes; + return new CloudStorageLimits + { + MaxUploadFileSize = Math.Min((long)quotaRemained, session.ServiceConfiguration.Limits.MaxUploadFileSize), + MaxChunkedUploadFileSize = Math.Min((long)quotaRemained, session.ServiceConfiguration.Limits.MaxChunkedUploadFileSize), + MaxDownloadFileSize = -1, + }; + } + + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(parent, name); + var uriString = GetResourceUrlInternal(session, path); + + int code; + var res = DropBoxRequestParser.RequestResourceByUrl(uriString, this, session, out code); + + if (res.Length == 0) + { + if (code != (int)HttpStatusCode.OK) + throw new SharpBoxException( + code == (int)HttpStatusCode.NotFound + ? SharpBoxErrorCodes.ErrorFileNotFound + : SharpBoxErrorCodes.ErrorCouldNotRetrieveDirectoryList, + new HttpException(Convert.ToInt32(code), "HTTP Error")); + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotRetrieveDirectoryList); + } + + // build the entry and subchilds + var entry = DropBoxRequestParser.CreateObjectsFromJsonString(res, this, session); + + var hash = entry.GetPropertyValue("hash"); + if (!string.IsNullOrEmpty(hash)) + { + DropBoxRequestParser.Addhash(uriString, hash, res, session); + } + // check if it was a deleted file + if (entry.IsDeleted) + return null; + + // set the parent + if (parent is BaseDirectoryEntry && parent.Id.Equals(entry.ParentID)) + (parent as BaseDirectoryEntry).AddChild(entry); + + return entry; + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + var path = GetResourceUrlInternal(session, DropBoxResourceIDHelpers.GetResourcePath(resource)); + + int code; + var res = DropBoxRequestParser.RequestResourceByUrl(path, this, session, out code); + + if (res.Length == 0) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotRetrieveDirectoryList); + + // build the entry and subchilds + DropBoxRequestParser.UpdateObjectFromJsonString(res, resource as BaseFileEntry, this, session); + + var hash = resource.GetPropertyValue("hash"); + if (!string.IsNullOrEmpty(hash)) + { + DropBoxRequestParser.Addhash(path, hash, res, session); + } + } + + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(parent, name); + + var parameters = new Dictionary + { + { "path", path }, + { "root", GetRootToken(session as DropBoxStorageProviderSession) } + }; + + int code; + var res = DropBoxRequestParser.RequestResourceByUrl(GetUrlString(DropBoxCreateFolder, session.ServiceConfiguration), parameters, this, session, out code); + if (res.Length != 0) + { + var entry = DropBoxRequestParser.CreateObjectsFromJsonString(res, this, session); + if (parent is BaseDirectoryEntry && parent.Id.Equals(entry.ParentID)) + (parent as BaseDirectoryEntry).AddChild(entry); + return entry; + } + + return null; + } + + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + var resourcePath = DropBoxResourceIDHelpers.GetResourcePath(entry); + + var parameters = new Dictionary + { + { "path", resourcePath }, + { "root", GetRootToken(session as DropBoxStorageProviderSession) } + }; + + try + { + int code; + DropBoxRequestParser.RequestResourceByUrl(GetUrlString(DropBoxDeleteItem, session.ServiceConfiguration), parameters, this, session, out code); + + var parent = entry.Parent as BaseDirectoryEntry; + if (parent != null) + { + parent.RemoveChildById(entry.Id); + } + } + catch (Exception) + { + return false; + } + + return true; + } + + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + var oldPath = DropBoxResourceIDHelpers.GetResourcePath(fsentry); + var path = DropBoxResourceIDHelpers.GetResourcePath(newParent, fsentry.Name); + + if (MoveOrRenameItem(session as DropBoxStorageProviderSession, fsentry as BaseFileEntry, path)) + { + // set the new parent + if (fsentry.Parent is BaseDirectoryEntry) + (fsentry.Parent as BaseDirectoryEntry).RemoveChildById(oldPath); + if (newParent is BaseDirectoryEntry) + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + + return true; + } + + return false; + } + + public override bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(newParent, fsentry.Name); + + // Move + if (CopyItem(session as DropBoxStorageProviderSession, fsentry as BaseFileEntry, path)) + { + // set the new parent + if (newParent != null && newParent is BaseDirectoryEntry) + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + + return true; + } + + return false; + } + + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(fsentry).ReplaceLast(fsentry.Name, newName); + return MoveOrRenameItem(session as DropBoxStorageProviderSession, fsentry as BaseFileEntry, path); + } + + public override void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token) + { + if (token is DropBoxRequestToken) + { + var requestToken = token as DropBoxRequestToken; + tokendata.Add(TokenDropBoxAppKey, requestToken.RealToken.TokenKey); + tokendata.Add(TokenDropBoxAppSecret, requestToken.RealToken.TokenSecret); + } + else + { + var dropboxToken = token as DropBoxToken; + tokendata.Add(TokenDropBoxCredPassword, dropboxToken.TokenSecret); + tokendata.Add(TokenDropBoxCredUsername, dropboxToken.TokenKey); + tokendata.Add(TokenDropBoxAppKey, dropboxToken.BaseTokenInformation.ConsumerKey); + tokendata.Add(TokenDropBoxAppSecret, dropboxToken.BaseTokenInformation.ConsumerSecret); + } + } + + public override ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + // get the credential type + var type = tokendata[CloudStorage.TokenCredentialType]; + + if (type.Equals(typeof (DropBoxToken).ToString())) + { + var tokenSecret = tokendata[TokenDropBoxCredPassword]; + var tokenKey = tokendata[TokenDropBoxCredUsername]; + + var bc = new DropBoxBaseTokenInformation + { + ConsumerKey = tokendata[TokenDropBoxAppKey], + ConsumerSecret = tokendata[TokenDropBoxAppSecret] + }; + + return new DropBoxToken(tokenKey, tokenSecret, bc); + } + if (type.Equals(typeof (DropBoxRequestToken).ToString())) + { + var tokenSecret = tokendata[TokenDropBoxAppSecret]; + var tokenKey = tokendata[TokenDropBoxAppKey]; + + return new DropBoxRequestToken(new OAuthToken(tokenKey, tokenSecret)); + } + + throw new InvalidCastException("Token type not supported through this provider"); + } + + public override string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, string additionalPath) + { + var path = DropBoxResourceIDHelpers.GetResourcePath(fileSystemEntry, additionalPath); + var basicUrl = session.ServiceConfiguration.ServiceLocator.ToString().TrimEnd('/'); + return !string.IsNullOrEmpty(path) ? basicUrl + "/" + path : basicUrl; + } + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + // build the url + var url = GetDownloadFileUrlInternal(session, fileSystemEntry); + + // build the service + var svc = new OAuthService(); + + // get the dropbox session + var dropBoxSession = session as DropBoxStorageProviderSession; + + // create webrequst + var requestProtected = svc.CreateWebRequest(url, WebRequestMethodsEx.Http.Get, null, null, dropBoxSession.Context, (DropBoxToken)dropBoxSession.SessionToken, null); + + // get the response + var response = svc.GetWebResponse(requestProtected); + + // get the data stream + var orgStream = svc.GetResponseStream(response); + + // build the download stream + var dStream = new BaseFileEntryDownloadStream(orgStream, fileSystemEntry); + + // put the disposable on the stack + dStream._DisposableObjects.Push(response); + + // go ahead + return dStream; + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + // build the url + var url = GetDownloadFileUrlInternal(session, fileSystemEntry.Parent); + + // get the session + var dbSession = session as DropBoxStorageProviderSession; + + // build service + var svc = new OAuthService(); + + // encode the filename + var fileName = fileSystemEntry.Name; + + // build oAuth parameter + var param = new Dictionary(); + param.Add("file", fileName); + + // sign the url + var signedUrl = svc.GetSignedUrl(url, dbSession.Context, dbSession.SessionToken as DropBoxToken, param); + + // build upload web request + var uploadRequest = svc.CreateWebRequestMultiPartUpload(signedUrl, null); + + // get the network stream + var ws = svc.GetRequestStreamMultiPartUpload(uploadRequest, fileName, uploadSize); + + // register the post dispose opp + ws.PushPostDisposeOperation(CommitUploadStream, svc, uploadRequest, uploadSize, fileSystemEntry, ws); + + // go ahead + return ws; + } + + public override bool SupportsDirectRetrieve + { + get { return true; } + } + + public void CommitUploadStream(params object[] arg) + { + // convert the args + var svc = arg[0] as OAuthService; + var uploadRequest = arg[1] as HttpWebRequest; + var uploadSize = (long)arg[2]; + var fileSystemEntry = arg[3] as BaseFileEntry; + + var requestStream = arg[4] as WebRequestStream; + + // check if all data was written into stream + if (requestStream.WrittenBytes != uploadRequest.ContentLength) + // nothing todo request was aborted + return; + + // perform the request + int code; + WebException e; + svc.PerformWebRequest(uploadRequest, null, out code, out e); + + // check the ret value + if (code != (int)HttpStatusCode.OK) + SharpBoxException.ThrowSharpBoxExceptionBasedOnHttpErrorCode(uploadRequest, (HttpStatusCode)code, e); + + if (fileSystemEntry != null) + { + fileSystemEntry.Length = uploadSize; + fileSystemEntry.Id = fileSystemEntry.ParentID != "/" ? fileSystemEntry.ParentID + "/" + fileSystemEntry.Name : fileSystemEntry.Name; + + var parent = fileSystemEntry.Parent as BaseDirectoryEntry; + if (parent != null) + { + parent.RemoveChildById(fileSystemEntry.Name); + parent.AddChild(fileSystemEntry); + } + } + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + } + + #region resumable uploads + + public override bool SupportsChunking + { + get { return true; } + } + + public override IResumableUploadSession CreateUploadSession(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long bytesToTransfer) + { + //return new ResumableUploadSession(fileSystemEntry, bytesToTransfer); + if (fileSystemEntry == null) throw new ArgumentNullException("fileSystemEntry"); + + return new ResumableUploadSession(fileSystemEntry.Id, fileSystemEntry.Name, fileSystemEntry.ParentID, bytesToTransfer); + } + + public override void UploadChunk(IStorageProviderSession session, IResumableUploadSession uploadSession, Stream stream, long chunkLength) + { + if (uploadSession.Status == ResumableUploadSessionStatus.Completed || uploadSession.Status == ResumableUploadSessionStatus.Aborted) + throw new InvalidOperationException("Upload session was either completed or aborted."); + + if (stream == null) + throw new ArgumentNullException("stream"); + + var requestParams = new Dictionary(); + if (uploadSession.Status == ResumableUploadSessionStatus.Started) + { + requestParams.Add("upload_id", uploadSession.GetItem("UploadId")); + requestParams.Add("offset", uploadSession.BytesTransfered.ToString()); + } + + var request = new OAuthService().CreateWebRequest(GetUrlString(DropBoxChunkedUpload, session.ServiceConfiguration), + "PUT", + null, + null, + ((DropBoxStorageProviderSession)session).Context, + (DropBoxToken)session.SessionToken, + requestParams); + + request.ContentLength = chunkLength; + using (var requestStream = request.GetRequestStream()) + { + stream.CopyTo(requestStream); + } + + using (var response = request.GetResponse()) + using (var responseStream = response.GetResponseStream()) + { + if (responseStream == null) return; + + var json = new JsonHelper(); + using (var streamReader = new StreamReader(responseStream)) + { + json.ParseJsonMessage(streamReader.ReadToEnd()); + } + + var uplSession = (ResumableUploadSession)uploadSession; + uplSession["UploadId"] = json.GetProperty("upload_id"); + uplSession["Expired"] = json.GetDateTimeProperty("expired"); + uplSession.BytesTransfered += chunkLength; + uplSession.Status = ResumableUploadSessionStatus.Started; + + if (uplSession.BytesToTransfer == uploadSession.BytesTransfered) + { + CommitUploadSession(session, uploadSession); + } + } + } + + public void CommitUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + if (uploadSession.Status == ResumableUploadSessionStatus.Started) + { + var requestService = new OAuthService(); + var request = requestService.CreateWebRequest(GetCommitUploadSessionUrl(session, uploadSession), + "POST", + null, + null, + ((DropBoxStorageProviderSession)session).Context, + (DropBoxToken)session.SessionToken, + new Dictionary { { "upload_id", uploadSession.GetItem("UploadId") } }); + + int httpStatusCode; + WebException httpException; + requestService.PerformWebRequest(request, null, out httpStatusCode, out httpException); + + if (httpStatusCode != (int)HttpStatusCode.OK) + SharpBoxException.ThrowSharpBoxExceptionBasedOnHttpErrorCode((HttpWebRequest)request, (HttpStatusCode)httpStatusCode, httpException); + + var rUploadSession = uploadSession as ResumableUploadSession; + rUploadSession.FileId = rUploadSession.ParentId != "/" ? rUploadSession.ParentId + "/" + rUploadSession.FileName : rUploadSession.FileName; + + + //var file = (BaseFileEntry)uploadSession.File; + //file.Length = uploadSession.BytesToTransfer; + //file.Id = file.ParentID != "/" ? file.ParentID + "/" + file.Name : file.Name; + + //var parent = file.Parent as BaseDirectoryEntry; + //if (parent != null) + //{ + // parent.RemoveChildById(file.Name); + // parent.AddChild(file); + //} + + ((ResumableUploadSession)uploadSession).Status = ResumableUploadSessionStatus.Completed; + } + } + + public override void AbortUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + if (uploadSession.Status != ResumableUploadSessionStatus.Completed) + { + ((ResumableUploadSession)uploadSession).Status = ResumableUploadSessionStatus.Aborted; + } + } + + #endregion + + #endregion + + #region Authorization Helper + + private DropBoxStorageProviderSession Authorize(DropBoxToken token, DropBoxConfiguration configuration) + { + // Get a valid dropbox session through oAuth authorization + var session = BuildSessionFromAccessToken(token, configuration); + + //( Get a valid root object + return GetRootBySessionExceptionHandled(session); + } + + private DropBoxStorageProviderSession GetRootBySessionExceptionHandled(DropBoxStorageProviderSession session) + { + try + { + var root = GetRootBySession(session); + + // return the infos + return root == null ? null : session; + } + catch (SharpBoxException ex) + { + // check if the exception an http error 403 + if (ex.InnerException is HttpException) + { + if ((((HttpException)ex.InnerException).GetHttpCode() == 403) || (((HttpException)ex.InnerException).GetHttpCode() == 401)) + throw new UnauthorizedAccessException(); + } + + // otherwise rethrow the old exception + throw ex; + } + } + + private ICloudDirectoryEntry GetRootBySession(DropBoxStorageProviderSession session) + { + // now check if we have application keys and secrets from a sandbox or a fullbox + // try to load the root of the full box if this fails we have only sandbox access + ICloudDirectoryEntry root; + + try + { + root = RequestResource(session, "/", null) as ICloudDirectoryEntry; + } + catch (SharpBoxException ex) + { + if (session.SandBoxMode) + throw ex; + else + { + // enable sandbox mode + session.SandBoxMode = true; + + // retry to get root object + root = RequestResource(session, "/", null) as ICloudDirectoryEntry; + } + } + + // go ahead + return root; + } + + public DropBoxStorageProviderSession BuildSessionFromAccessToken(DropBoxToken token, DropBoxConfiguration configuration) + { + // build the consumer context + var consumerContext = new OAuthConsumerContext(token.BaseTokenInformation.ConsumerKey, token.BaseTokenInformation.ConsumerSecret); + + // build the session + var session = new DropBoxStorageProviderSession(token, configuration, consumerContext, this); + + // go aahead + return session; + } + + private static string GetRootToken(DropBoxStorageProviderSession session) + { + return session.SandBoxMode ? "sandbox" : "dropbox"; + } + + private bool MoveOrRenameItem(DropBoxStorageProviderSession session, BaseFileEntry orgEntry, string toPath) + { + return MoveOrRenameOrCopyItem(session, orgEntry, toPath, false); + } + + private bool CopyItem(DropBoxStorageProviderSession session, BaseFileEntry orgEntry, string toPath) + { + return MoveOrRenameOrCopyItem(session, orgEntry, toPath, true); + } + + private bool MoveOrRenameOrCopyItem(DropBoxStorageProviderSession session, BaseFileEntry orgEntry, string toPath, bool copy) + { + // build the path for resource + var resourcePath = DropBoxResourceIDHelpers.GetResourcePath(orgEntry); + + // request the json object via oauth + var parameters = new Dictionary + { + { "from_path", resourcePath }, + { "root", GetRootToken(session) }, + { "to_path", toPath } + }; + + try + { + // move or rename the entry + int code; + var res = DropBoxRequestParser.RequestResourceByUrl(GetUrlString(copy ? DropBoxCopyItem : DropBoxMoveItem, session.ServiceConfiguration), parameters, this, session, out code); + + // update the entry + DropBoxRequestParser.UpdateObjectFromJsonString(res, orgEntry, this, session); + } + catch (Exception) + { + return false; + } + + orgEntry.Id = toPath; + return true; + } + + private static string GetResourceUrlInternal(IStorageProviderSession session, string path) + { + if (session is DropBoxStorageProviderSession) + { + var dbSession = session as DropBoxStorageProviderSession; + String uri = PathHelper.Combine(dbSession.SandBoxMode + ? GetUrlString(DropBoxSandboxRoot, session.ServiceConfiguration) + : GetUrlString(DropBoxDropBoxRoot, session.ServiceConfiguration), + HttpUtilityEx.UrlEncodeUTF8(path)); + return uri; + } + return null; + } + + public static string GetDownloadFileUrlInternal(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + // cast varibales + var dropBoxSession = session as DropBoxStorageProviderSession; + + // gather information + var rootToken = GetRootToken(dropBoxSession); + var dropboxPath = DropBoxResourceIDHelpers.GetResourcePath(entry); + + // add all information to url; + var url = GetUrlString(DropBoxUploadDownloadFile, session.ServiceConfiguration) + "/" + rootToken; + + if (dropboxPath.Length > 0 && dropboxPath[0] != '/') + url += "/"; + + url += HttpUtilityEx.UrlEncodeUTF8(dropboxPath); + + return url; + } + + public static string GetCommitUploadSessionUrl(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + var rUploadSession = uploadSession as ResumableUploadSession; + if (rUploadSession == null) throw new ArgumentNullException("uploadSession"); + + return GetUrlString(DropBoxCommitChunkedUpload, session.ServiceConfiguration) + + "/" + GetRootToken((DropBoxStorageProviderSession)session) + + "/" + HttpUtilityEx.UrlEncodeUTF8(DropBoxResourceIDHelpers.GetResourcePath(null, rUploadSession.FileName, rUploadSession.ParentId)); + } + + #endregion + + #region API URL helper + + public static string GetUrlString(string urltemplate, ICloudStorageConfiguration configuration) + { + if (urltemplate.Contains("{0}")) + { + if (configuration == null || !(configuration is DropBoxConfiguration)) + return string.Format(urltemplate, ((int)DropBoxAPIVersion.Stable).ToString()); + + var versionValue = (int)((DropBoxConfiguration)configuration).APIVersion; + return string.Format(urltemplate, versionValue.ToString()); + } + + return urltemplate; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderSession.cs new file mode 100644 index 0000000000..f65fa3b475 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/DropBox/Logic/DropBoxStorageProviderSession.cs @@ -0,0 +1,31 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic +{ + internal class DropBoxStorageProviderSession : IStorageProviderSession + { + public OAuthConsumerContext Context { get; set; } + + public bool SandBoxMode { get; set; } + + public DropBoxStorageProviderSession(DropBoxToken token, DropBoxConfiguration config, OAuthConsumerContext consumerContext, IStorageProviderService service) + { + SessionToken = token; + ServiceConfiguration = config; + Service = service; + Context = consumerContext; + } + + #region IStorageProviderSession Members + + public ICloudStorageAccessToken SessionToken { get; private set; } + + public IStorageProviderService Service { get; private set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpConfiguration.cs new file mode 100644 index 0000000000..b271c7bb70 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpConfiguration.cs @@ -0,0 +1,50 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.FTP +{ + /// + /// This class implements all FTP specific configurations + /// + public class FtpConfiguration : ICloudStorageConfiguration + { + private bool _trustUnsecureSslConnections; + + /// + /// ctor of the FTP configuration + /// + public FtpConfiguration(Uri uriFtpServer) + { + ServiceLocator = uriFtpServer; + } + + /// + /// Specifies if we allow not secure ssl connections + /// + public bool TrustUnsecureSSLConnections + { + get { return _trustUnsecureSslConnections; } + set { _trustUnsecureSslConnections = value; } + } + + #region ICloudStorageConfiguration Members + + private CloudStorageLimits _limits = new CloudStorageLimits(); + + /// + /// Sets or gets the limits of a webdav configuration + /// + public CloudStorageLimits Limits + { + get { return _limits; } + + set { _limits = value; } + } + + /// + /// Gets the FTP service url + /// + public Uri ServiceLocator { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpStorageProvider.cs new file mode 100644 index 0000000000..e139f27072 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/FtpStorageProvider.cs @@ -0,0 +1,12 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.FTP.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.FTP +{ + internal class FtpStorageProvider : GenericStorageProvider + { + public FtpStorageProvider() + : base(new CachedServiceWrapper(new FtpStorageProviderService())) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderService.cs new file mode 100644 index 0000000000..172a0f0ef0 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderService.cs @@ -0,0 +1,353 @@ +// ---------------------------------------------------------------------------------------- +// FTP Provider Functions - by Fungusware [www.fungusware.com] +// ---------------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Net; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web.Ftp; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using System.Text.RegularExpressions; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.FTP.Logic +{ + internal class FtpStorageProviderService : GenericStorageProviderService + { + private readonly FtpService _ftpService = new FtpService(); + + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return (token is ICredentials); + } + + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + // cast the creds to the right type + var creds = token as GenericNetworkCredentials; + + // check if url available + int status; + WebException e; + _ftpService.PerformSimpleWebCall(configuration.ServiceLocator.ToString(), WebRequestMethods.Ftp.ListDirectory, creds.GetCredential(null, null), null, out status, out e); + if (status == (int)FtpStatusCode.NotLoggedIn) + throw new UnauthorizedAccessException(); + if (status >= 100 && status < 400) + return new FtpStorageProviderSession(token, configuration as FtpConfiguration, this); + return null; + } + + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + //declare the requested entry + ICloudFileSystemEntry fsEntry; + + // lets have a look if we are on the root node + if (parent == null) + { + // just create the root entry + fsEntry = GenericStorageProviderFactory.CreateDirectoryEntry(session, name, parent); + } + else + { + // ok we have a parent, let's retrieve the resource + // from his child list + fsEntry = parent.GetChild(name, false); + } + + // now that we create the entry just update the chuld + if (fsEntry is ICloudDirectoryEntry) + RefreshResource(session, fsEntry as ICloudDirectoryEntry); + + // go ahead + return fsEntry; + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + // nothing to do for files + if (!(resource is ICloudDirectoryEntry)) + return; + + // Refresh schild + RefreshChildsOfDirectory(session, resource as ICloudDirectoryEntry); + } + + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + // get the creds + var creds = ((GenericNetworkCredentials)session.SessionToken).GetCredential(null, null); + + // generate the loca path + var uriPath = GetResourceUrl(session, entry, null); + + // removed the file + if (entry is ICloudDirectoryEntry) + { + // we need an empty directory + foreach (var child in (ICloudDirectoryEntry)entry) + { + DeleteResource(session, child); + } + + // remove the directory + return _ftpService.FtpDeleteEmptyDirectory(uriPath, creds); + } + + // remove the file + return _ftpService.FtpDeleteFile(uriPath, creds); + } + + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + // get credentials + var creds = ((GenericNetworkCredentials)session.SessionToken).GetCredential(null, null); + + // get old name uri + var uriPath = GetResourceUrl(session, fsentry.Parent, fsentry.Name); + + // get the new path + var targetPath = PathHelper.Combine(GenericHelper.GetResourcePath(newParent), fsentry.Name); + + // do it + if (!_ftpService.FtpRename(uriPath, targetPath, creds)) + return false; + + // remove from parent + (fsentry.Parent as BaseDirectoryEntry).RemoveChild(fsentry as BaseFileEntry); + + // add to new parent + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + + return true; + } + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + // get the session creds + var creds = session.SessionToken as ICredentials; + + // get the full path + var uriPath = GetResourceUrl(session, fileSystemEntry, null); + + // get the ftp request + var ftp = (FtpWebRequest)_ftpService.CreateWebRequest(uriPath, WebRequestMethodsEx.Ftp.DownloadFile, creds, false, null); + + // set request to download a file in binary mode + ftp.UseBinary = true; + + // create the response + using (var response = _ftpService.GetWebResponse(ftp)) + { + // get the data + var orgStream = _ftpService.GetResponseStream(response); + + var dStream = new BaseFileEntryDownloadStream(orgStream, fileSystemEntry); + + // put the disposable on the stack + dStream._DisposableObjects.Push(response); + + // go ahead + return dStream; + } + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + // build the url + var url = GetResourceUrl(session, fileSystemEntry, null); + + // get the session creds + var creds = session.SessionToken as ICredentials; + + // build the webrequest + var networkRequest = (FtpWebRequest)_ftpService.CreateWebRequest(url, WebRequestMethodsEx.Ftp.UploadFile, creds, false, null); + + // set the binary mode + networkRequest.UseBinary = true; + + // Notify FTP of the expected size + networkRequest.ContentLength = uploadSize; + + // get the request stream + var requestStream = _ftpService.GetRequestStream(networkRequest, uploadSize); + + // add disposal opp + requestStream.PushPostDisposeOperation(CommitUploadStream, _ftpService, networkRequest, fileSystemEntry, requestStream); + + // go ahead + return requestStream; + } + + public override bool SupportsDirectRetrieve + { + get { return false; } + } + + public void CommitUploadStream(params object[] arg) + { + // convert the args + // FtpService svc = arg[0] as FtpService; + var uploadRequest = arg[1] as FtpWebRequest; + var fileSystemEntry = arg[2] as BaseFileEntry; + + var requestStream = arg[3] as WebRequestStream; + + // close the stream + requestStream.Close(); + + // close conncetion + uploadRequest.Abort(); + + // check if all data was written into stream + if (requestStream.WrittenBytes != uploadRequest.ContentLength) + // nothing todo request was aborted + return; + // adjust the lengt + fileSystemEntry.Length = uploadRequest.ContentLength; + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + } + + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + // get credentials + var creds = ((GenericNetworkCredentials)session.SessionToken).GetCredential(null, null); + + // build the full url + var resFull = GetResourceUrl(session, parent, name); + + // create the director + if (_ftpService.FtpCreateDirectory(resFull, creds)) + { + // create the filesystem object + var fsEntry = GenericStorageProviderFactory.CreateDirectoryEntry(session, name, parent); + + // go ahead + return fsEntry; + } + return null; + } + + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + // get credentials + var creds = ((GenericNetworkCredentials)session.SessionToken).GetCredential(null, null); + + // get old name uri + var uriPath = GetResourceUrl(session, fsentry.Parent, fsentry.Name); + + // get the new path + var TargetPath = PathHelper.Combine(GenericHelper.GetResourcePath(fsentry.Parent), newName); + + // do it + if (!_ftpService.FtpRename(uriPath, TargetPath, creds)) + return false; + + // rename the entry + var fentry = fsentry as BaseFileEntry; + fentry.Name = newName; + + // go ahead + return true; + } + + #region Helper + + private void RefreshChildsOfDirectory(IStorageProviderSession session, ICloudDirectoryEntry dir) + { + // get the creds + var creds = ((GenericNetworkCredentials)session.SessionToken).GetCredential(null, null); + + // get the uri + var resSource = GetResourceUrl(session, dir.Parent, dir.Name); + + // clear all childs + GenericStorageProviderFactory.ClearAllChilds(dir); + + // we need to request a directory list here + using (var data = _ftpService.PerformSimpleWebCall(resSource, WebRequestMethodsEx.Ftp.ListDirectoryDetails, creds, null)) + { + using (var r = new StreamReader(data)) + { + while (!r.EndOfStream) + { + var ftpline = r.ReadLine(); + + var m = GetMatchingRegexFromFTPLine(ftpline); + + if (m == null) + { + //failed + throw new ApplicationException("Unable to parse line: " + ftpline); + } + + // get the filename + var filename = m.Groups["name"].Value; + + // get teh modified date + var fileDateTime = DateTime.MinValue; + try + { + fileDateTime = DateTime.Parse(m.Groups["timestamp"].Value); + } + catch (Exception) + { + } + + // evaluate if we have a directory + var _dir = m.Groups["dir"].Value; + if ((!string.IsNullOrEmpty(_dir) & _dir != "-")) + { + GenericStorageProviderFactory.CreateDirectoryEntry(session, filename, fileDateTime, dir); + } + else + { + // get the size + var size = Convert.ToInt64(m.Groups["size"].Value); + + // create the file object + GenericStorageProviderFactory.CreateFileSystemEntry(session, filename, fileDateTime, size, dir); + } + } + } + } + } + + /// + /// List of REGEX formats for different FTP server listing formats + /// + /// + /// The first three are various UNIX/LINUX formats, fourth is for MS FTP + /// in detailed mode and the last for MS FTP in 'DOS' mode. + /// I wish VB.NET had support for Const arrays like C# but there you go + /// + private static readonly string[] ParseFormats = + { + "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{4})\\s+(?.+)", + "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{4})\\s+(?.+)", + "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\d+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?.+)", + "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})\\s+\\d+\\s+\\w+\\s+\\w+\\s+(?\\d+)\\s+(?\\w+\\s+\\d+\\s+\\d{1,2}:\\d{2})\\s+(?.+)", + "(?[\\-d])(?([\\-r][\\-w][\\-xs]){3})(\\s+)(?(\\d+))(\\s+)(?(\\w+\\s\\w+))(\\s+)(?(\\d+))\\s+(?\\w+\\s+\\d+\\s+\\d{2}:\\d{2})\\s+(?.+)", + "(?\\d{2}\\-\\d{2}\\-\\d{2}\\s+\\d{2}:\\d{2}[Aa|Pp][mM])\\s+(?\\<\\w+\\>){0,1}(?\\d+){0,1}\\s+(?.+)" + }; + + private static Match GetMatchingRegexFromFTPLine(string ftpline) + { + for (var i = 0; i <= ParseFormats.Length - 1; i++) + { + var rx = new Regex(ParseFormats[i]); + var m = rx.Match(ftpline); + if (m.Success) + return m; + } + return null; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderSession.cs new file mode 100644 index 0000000000..53325e1b3d --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/Ftp/Logic/FtpStorageProviderSession.cs @@ -0,0 +1,24 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.FTP.Logic +{ + internal class FtpStorageProviderSession : IStorageProviderSession + { + public FtpStorageProviderSession(ICloudStorageAccessToken token, FtpConfiguration config, IStorageProviderService service) + { + SessionToken = token; + ServiceConfiguration = config; + Service = service; + } + + #region IStorageProviderSession Members + + public ICloudStorageAccessToken SessionToken { get; private set; } + + public IStorageProviderService Service { get; private set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericCurrentCredentials.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericCurrentCredentials.cs new file mode 100644 index 0000000000..2d607db0c2 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericCurrentCredentials.cs @@ -0,0 +1,28 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider +{ + /// + /// This class contains the needed access credentials for a specific webdav + /// user + /// + public class GenericCurrentCredentials : ICloudStorageAccessToken, ICredentials + { + #region ICredentials Members + + /// + /// Returns the network credentials which can be used in webrequest. This method + /// uses the standard credentials of the logged on user + /// + /// + /// + /// + public virtual NetworkCredential GetCredential(Uri uri, string authType) + { + return CredentialCache.DefaultNetworkCredentials; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericNetworkCredentials.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericNetworkCredentials.cs new file mode 100644 index 0000000000..c6f0b8564a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericNetworkCredentials.cs @@ -0,0 +1,45 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider +{ + /// + /// This class contains the needed access credentials for a specific webdav + /// user + /// + public class GenericNetworkCredentials : GenericCurrentCredentials + { + /// + /// Useraccount of the end user with access to the WebDav share + /// + public string UserName { get; set; } + + /// + /// Password of the end user with access to the WebDav share + /// + public string Password { get; set; } + + /// + /// returns network credentials which are usable in a webrequest + /// + /// + /// + /// + public override NetworkCredential GetCredential(Uri uri, string authType) + { + if (UserName.Contains("\\")) + { + var domain = UserName.Split('\\')[0]; + var user = UserName.Split('\\')[1]; + + return new NetworkCredential(user, Password, domain); + } + return new NetworkCredential(UserName, Password); + } + + public override string ToString() + { + return string.Format("{0}+{1}", UserName, Password); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProvider.cs new file mode 100644 index 0000000000..ec176df266 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProvider.cs @@ -0,0 +1,305 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider +{ + /// + /// The generic storage provider class implements platform independent logic as + /// base for all managed storage provider. All platform specific logic has to be implemented + /// in the storage provider service interface + /// + public class GenericStorageProvider : ICloudStorageProviderInternal + { + /// + /// A specific implementation of a storage service interface which contains + /// all provider specific logic + /// + protected IStorageProviderService Service; + + /// + /// A provider specific implementation of a session + /// + protected IStorageProviderSession Session; + + /// + /// The constructure need a specific service implementation + /// + /// + public GenericStorageProvider(IStorageProviderService service) + { + Service = service; + } + + #region ICloudStorageProvider Members + + /// + /// This method opens a session for the implemented storage provider based on an existing + /// security token. + /// + /// + /// + /// + public ICloudStorageAccessToken Open(ICloudStorageConfiguration configuration, ICloudStorageAccessToken token) + { + // Verify the compatibility of the credentials + if (!Service.VerifyAccessTokenType(token)) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidCredentialsOrConfiguration); + + // create a new session + Session = Service.CreateSession(token, configuration); + + // check the session + if (Session == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidCredentialsOrConfiguration); + + // return the accesstoken token + return Session.SessionToken; + } + + /// + /// This method closes the established session to a service provider + /// + public void Close() + { + // close the session + Service.CloseSession(Session); + + // remove reference + Session = null; + } + + /// + /// This methid returns the root node of the virtual filesystem which + /// is abstracted by SharpBox + /// + /// + public ICloudDirectoryEntry GetRoot() + { + return Service.RequestResource(Session, "/", null) as ICloudDirectoryEntry; + } + + /// + /// This method returns a filesystem object, this can be files or folders + /// + /// + /// + /// + public ICloudFileSystemEntry GetFileSystemObject(string path, ICloudDirectoryEntry parent) + { + /* + * This section generates for every higher object the object tree + */ + var ph = new PathHelper(path); + var elements = ph.GetPathElements(); + + // create the virtual root + var current = parent ?? GetRoot(); + + // build the root + + // check if we request only the root + if (path.Equals("/")) + return current; + + if (Service.SupportsDirectRetrieve) + { + //Request directly + return Service.RequestResource(Session, path.TrimStart('/'), current); + } + + // create the path tree + for (var i = 0; i <= elements.Length - 1; i++) + { + var elem = elements[i]; + + if (i == elements.Length - 1) + { + return current.GetChild(elem, false); + } + + try + { + current = current.GetChild(elem, true) as ICloudDirectoryEntry; + } + catch (SharpBoxException e) + { + // if not found, create a virtual one + if (e.ErrorCode == SharpBoxErrorCodes.ErrorFileNotFound) + current = GenericStorageProviderFactory.CreateDirectoryEntry(Session, elem, current); + else + throw; + } + } + + // looks like an error + return null; + } + + /// + /// This method creates a folder in a given parent folder. + /// Override this if your storage support resources having same name in one folder. + /// + /// + /// + /// + public virtual ICloudDirectoryEntry CreateFolder(string name, ICloudDirectoryEntry parent) + { + // solve the parent issue + if (parent == null) + { + parent = GetRoot(); + + if (parent == null) + return null; + } + + // Don't support resources having same name in one folder by default + var child = parent.FirstOrDefault(x => x.Name.Equals(name) && x is ICloudDirectoryEntry); + if (child != null) + return child as ICloudDirectoryEntry; + + return Service.CreateResource(Session, name, parent) as ICloudDirectoryEntry; + } + + /// + /// This method removes a given filesystem object from the cloud storage + /// + /// + /// + public bool DeleteFileSystemEntry(ICloudFileSystemEntry fsentry) + { + return Service.DeleteResource(Session, fsentry); + } + + /// + /// This method moves a specifc filesystem object from his current location + /// into a new folder + /// + /// + /// + /// + public bool MoveFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + return Service.MoveResource(Session, fsentry, newParent); + } + + /// + /// This method moves a specifc filesystem object from his current location + /// into a new folder + /// + /// + /// + /// + public bool CopyFileSystemEntry(ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + return Service.CopyResource(Session, fsentry, newParent); + } + + /// + /// This method renames a given filesystem object (file or folder) + /// + /// + /// + /// + public bool RenameFileSystemEntry(ICloudFileSystemEntry fsentry, string newName) + { + // save the old name + var renamedId = fsentry.Id; + + // rename the resource + if (Service.RenameResource(Session, fsentry, newName)) + { + // get the parent + var p = fsentry.Parent as BaseDirectoryEntry; + + // remove the old childname + p.RemoveChildById(renamedId); + + // readd the child + p.AddChild(fsentry as BaseFileEntry); + + // go ahead + return true; + } + return false; + } + + /// + /// This method creates a file in the cloud storage + /// + /// + /// + /// + public virtual ICloudFileSystemEntry CreateFile(ICloudDirectoryEntry parent, string name) + { + // build the parent + if (parent == null) + parent = GetRoot(); + + // build the file entry + var newEntry = GenericStorageProviderFactory.CreateFileSystemEntry(Session, name, parent); + return newEntry; + } + + /// + /// This method returns the absolut URL (with all authentication decorators) for a specific file + /// system object + /// + /// + /// + /// + public virtual Uri GetFileSystemObjectUrl(string path, ICloudDirectoryEntry parent) + { + var url = Service.GetResourceUrl(Session, parent, path); + return new Uri(url); + } + + /// + /// This method returns the filesystem path (UNIX style) of a specific object + /// + /// + /// + public virtual string GetFileSystemObjectPath(ICloudFileSystemEntry fsObject) + { + if (fsObject is ICloudDirectoryEntry) + return GenericHelper.GetResourcePath(fsObject); + + return GenericHelper.GetResourcePath(fsObject.Parent) + "/" + fsObject.Id; + } + + /// + /// This method stores the given security token into a tokendictionary + /// + /// + /// + public void StoreToken(Dictionary tokendata, ICloudStorageAccessToken token) + { + Service.StoreToken(Session, tokendata, token); + } + + /// + /// This method loads the given token from the token dictionary + /// + /// + /// + public ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + return Service.LoadToken(tokendata); + } + + /// + /// This property returns the current accesstoken + /// + public ICloudStorageAccessToken CurrentAccessToken + { + get { return Session == null ? null : Session.SessionToken; } + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProviderService.cs new file mode 100644 index 0000000000..ab8d8a42a1 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GenericStorageProviderService.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.IO; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.Exceptions; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider +{ + /// + /// This class has to be used in combination with the GenericStorageProvider class + /// and supports all generic logic on the service level + /// + public abstract class GenericStorageProviderService : IStorageProviderService + { + internal const string TokenGenericCredUsername = "TokenCredGenericUsername"; + internal const string TokenGenericCredPassword = "TokenCredGenericPassword"; + + /// + /// This method verifies if the given configuration is compatible to the implemented + /// service provider. + /// + /// + /// + public abstract bool VerifyAccessTokenType(ICloudStorageAccessToken token); + + /// + /// This method generates a session to a webdav share via access token + /// + /// + /// + /// + public abstract IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration); + + /// + /// This method closes the session + /// + /// + public virtual void CloseSession(IStorageProviderSession session) + { + // nothing to do here + } + + public virtual CloudStorageLimits GetLimits(IStorageProviderSession session) + { + return session.ServiceConfiguration.Limits; + } + + /// + /// This method request a directory entry from the storage provider service + /// + /// + /// + /// + /// + public abstract ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent); + + /// + /// This method updates the locally cache resource metadata from the storage service + /// + /// + /// + public abstract void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource); + + /// + /// This method removes a resource in the storage provider service + /// + /// + /// + /// + public abstract bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry); + + /// + /// This method deletes a resource in the storage provider service + /// + /// + /// + /// + /// + public abstract bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent); + + + /// + /// This method deletes a resource in the storage provider service + /// + /// + /// + /// + /// + public virtual bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + throw new NotSupportedException("This operation is not supported"); + } + + /// + /// Writes a generic token onto the storage collection + /// + /// + /// + /// + public virtual void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token) + { + if (token is GenericNetworkCredentials) + { + var creds = token as GenericNetworkCredentials; + tokendata.Add(TokenGenericCredUsername, creds.UserName); + tokendata.Add(TokenGenericCredPassword, creds.Password); + } + } + + /// + /// Reads the token information + /// + /// + /// + public virtual ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + ICloudStorageAccessToken at = null; + + var type = tokendata[CloudStorage.TokenCredentialType]; + + if (type.Equals(typeof (GenericNetworkCredentials).ToString())) + { + var username = tokendata[TokenGenericCredUsername]; + var password = tokendata[TokenGenericCredPassword]; + + var bc = new GenericNetworkCredentials { UserName = username, Password = password }; + + at = bc; + } + else if (type.Equals(typeof (GenericCurrentCredentials).ToString())) + { + at = new GenericCurrentCredentials(); + } + + return at; + } + + /// + /// This method build up a valid resource url + /// + /// + /// + /// + /// + public virtual string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, string additionalPath) + { + additionalPath = !string.IsNullOrEmpty(additionalPath) ? additionalPath.Trim('/') : string.Empty; + var url = session.ServiceConfiguration.ServiceLocator.ToString().Trim('/'); + var entryPath = fileSystemEntry != null ? GenericHelper.GetResourcePath(fileSystemEntry).Trim('/') : string.Empty; + if (!string.IsNullOrEmpty(entryPath)) + { + url += "/" + entryPath; + } + if (!string.IsNullOrEmpty(additionalPath)) + { + url += "/" + additionalPath; + } + return url; + } + + /// + /// This methid download the content of a file resource into a target download stream + /// + /// + /// + /// + /// + /// + public virtual void DownloadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext) + { + // build the download stream + using (var data = CreateDownloadStream(session, fileSystemEntry)) + { + // copy the data + var res = StreamHelper.CopyStreamData(this, data, targetDataStream, CloudStorage.FileStreamCopyCallback, progressCallback, fileSystemEntry, progressContext); + if (res.ResultCode == StreamHelperResultCodes.Aborted) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorTransferAbortedManually); + + // commit everything + CommitStreamOperation(session, fileSystemEntry, nTransferDirection.nDownload, data); + } + } + + /// + /// This method establishes a download stream with the storage service + /// + /// + /// + /// + public abstract Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry); + + /// + /// This method establishes an upload stream with the storage service + /// + /// + /// + /// + /// + public abstract Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize); + + public abstract bool SupportsDirectRetrieve { get; } + + #region resumable upload + + public virtual bool SupportsChunking + { + get { return false; } + } + + public virtual IResumableUploadSession CreateUploadSession(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long bytesToTransfer) + { + throw ResumableUploadNotSupported(); + } + + public virtual void AbortUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + throw ResumableUploadNotSupported(); + } + + public virtual void UploadChunk(IStorageProviderSession session, IResumableUploadSession uploadSession, Stream stream, long chunkLength) + { + throw ResumableUploadNotSupported(); + } + + private static NotSupportedException ResumableUploadNotSupported() + { + return new NotSupportedException("Provider does not supports resumable uploads."); + } + + #endregion + + /// + /// This method commits a stream operation before the disposabl method of the stream will be called + /// + /// + /// + /// + /// + public abstract void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream); + + /// + /// This method uploads data into a file resource + /// + /// + /// + /// + /// + /// + public virtual void UploadResourceContent(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, Stream targetDataStream, FileOperationProgressChanged progressCallback, object progressContext) + { + // build the stream stream + using (var data = CreateUploadStream(session, fileSystemEntry, targetDataStream.Length)) + { + // copy the data + var res = StreamHelper.CopyStreamData(this, targetDataStream, data, CloudStorage.FileStreamCopyCallback, progressCallback, fileSystemEntry, progressContext); + if (res.ResultCode == StreamHelperResultCodes.Aborted) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorTransferAbortedManually); + + // flush the upload stream to clean the caches + data.Flush(); + + // commit everything + CommitStreamOperation(session, fileSystemEntry, nTransferDirection.nUpload, data); + } + } + + /// + /// This methid creates a directory object in the storage service + /// + /// + /// + /// + /// + public abstract ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent); + + /// + /// This method renames a resource in the storage service + /// + /// + /// + /// + /// + public abstract bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName); + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsAuthorizationHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsAuthorizationHelper.cs new file mode 100644 index 0000000000..6420fac222 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsAuthorizationHelper.cs @@ -0,0 +1,75 @@ +using System; +using System.Text; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Impl; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + public static class GoogleDocsAuthorizationHelper + { + public static GoogleDocsRequestToken GetGoogleDocsRequestToken(GoogleDocsConfiguration configuration, string consumerKey, string consumerSecret) + { + var consumerContext = new OAuthConsumerContext(consumerKey, consumerSecret); + var serviceContext = new OAuthServiceContext(GetRequestTokenUrl(configuration), + configuration.OAuthAuthorizeTokenUrl.ToString(), + configuration.AuthorizationCallBack.ToString(), + GetAccessTokenUrl(configuration, null)); + var service = new OAuthService(); + var token = service.GetRequestToken(serviceContext, consumerContext); + return token != null ? new GoogleDocsRequestToken(token) : null; + } + + public static string GetGoogleDocsAuthorizationUrl(GoogleDocsConfiguration configuration, GoogleDocsRequestToken token) + { + return OAuthUrlGenerator.GenerateAuthorizationUrl(configuration.OAuthAuthorizeTokenUrl.ToString(), + configuration.AuthorizationCallBack.ToString(), + token.RealToken); + } + + public static ICloudStorageAccessToken ExchangeGoogleDocsRequestTokenIntoAccessToken(GoogleDocsConfiguration configuration, string consumerKey, string consumerSecret, GoogleDocsRequestToken requestToken, string oAuthVerifier) + { + var consumerContext = new OAuthConsumerContext(consumerKey, consumerSecret); + var serviceContext = new OAuthServiceContext(configuration.OAuthGetRequestTokenUrl.ToString(), + configuration.OAuthAuthorizeTokenUrl.ToString(), + configuration.AuthorizationCallBack.ToString(), + GetAccessTokenUrl(configuration, oAuthVerifier)); + var service = new OAuthService(); + var accessToken = service.GetAccessToken(serviceContext, consumerContext, requestToken.RealToken); + if (accessToken == null) throw new UnauthorizedAccessException(); + return new GoogleDocsToken(accessToken, consumerKey, consumerSecret); + } + + public static ICloudStorageAccessToken BuildToken(string tokenKey, string tokenSecret, string consumerKey, string consumerSecret) + { + return new GoogleDocsToken(OAuthBase.UrlEncode(tokenKey), OAuthBase.UrlEncode(tokenSecret), consumerKey, consumerSecret); + } + + private static string GetAccessTokenUrl(GoogleDocsConfiguration configuration, string oAuthVerifier) + { + var accessTokenUrl = configuration.OAuthGetAccessTokenUrl.ToString(); + + if (!string.IsNullOrEmpty(oAuthVerifier)) + { + accessTokenUrl = string.Format("{0}?oauth_verifier={1}", accessTokenUrl, oAuthVerifier); + } + + return accessTokenUrl; + } + + private static string GetRequestTokenUrl(GoogleDocsConfiguration configuration) + { + var requestTokenUrl = configuration.OAuthGetRequestTokenUrl.ToString(); + + if (!string.IsNullOrEmpty(configuration.AccessUrlScope)) + { + var sb = new StringBuilder(requestTokenUrl); + sb.AppendFormat("?scope={0}", OAuthBase.UrlEncode(configuration.AccessUrlScope, '.')); + sb.AppendFormat("&oauth_callback={0}", OAuthBase.UrlEncode(configuration.AuthorizationCallBack.ToString(), '.')); + requestTokenUrl = sb.ToString(); + } + + return requestTokenUrl; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConfiguration.cs new file mode 100644 index 0000000000..a48bce3b0b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConfiguration.cs @@ -0,0 +1,62 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + public class GoogleDocsConfiguration : ICloudStorageConfiguration + { + public GoogleDocsConfiguration() + : this(new Uri(GoogleDocsConstants.GoogleDocsBaseUrl)) + { + } + + public GoogleDocsConfiguration(Uri serviceLocator) + { + ServiceLocator = serviceLocator; + AuthorizationCallBack = new Uri(GoogleDocsConstants.CallbackDefaultUrl); + } + + public static GoogleDocsConfiguration GetStandartConfiguration() + { + return new GoogleDocsConfiguration(); + } + + public Uri OAuthGetRequestTokenUrl + { + get { return new Uri(GoogleDocsConstants.OAuthGetRequestUrl); } + } + + public Uri OAuthAuthorizeTokenUrl + { + get { return new Uri(GoogleDocsConstants.OAuthAuthorizeUrl); } + } + + public Uri OAuthGetAccessTokenUrl + { + get { return new Uri(GoogleDocsConstants.OAuthGetAccessUrl); } + } + + public string AccessUrlScope + { + get { return GoogleDocsConstants.BasicScopeUrl; } + } + + public Uri AuthorizationCallBack { get; set; } + + public Uri ServiceLocator { get; private set; } + + public bool TrustUnsecureSSLConnections + { + get { return false; } + } + + public CloudStorageLimits Limits + { + get { return new CloudStorageLimits(2L*1024L*1024L*1024L, -1) { MaxChunkedUploadFileSize = -1 }; } + } + + public string GDataVersion + { + get { return "3.0"; } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConstants.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConstants.cs new file mode 100644 index 0000000000..f1d7838fa7 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsConstants.cs @@ -0,0 +1,51 @@ +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + internal class GoogleDocsConstants + { + public const string TokenGoogleDocsAppKey = "TokenGoogleDocsAppKey"; + public const string TokenGoogleDocsAppSecret = "TokenGoogleDocsAppSecret"; + public const string TokenGoogleDocsUsername = "TokenGoogleDocsUsername"; + public const string TokenGoogleDocsPassword = "TokenGoogleDocsPassword"; + + public const string EtagProperty = "GoogleDocsEtag"; + public const string KindProperty = "GoogleDocsKind"; + public const string ResCreateMediaProperty = "GoogleDocsResumableCreateMedia"; + public const string ResEditMediaProperty = "GoogleDocsResumableEditMedia"; + public const string DownloadUrlProperty = "GoogleDocsDownload"; + public const string ParentsProperty = "GoogleDocsParents"; + + //api access points + public const string GoogleDocsBaseUrl = "https://drive.google.com"; + public const string GoogleDocsFeedUrl = GoogleDocsBaseUrl + "/feeds/default/private/full"; + public const string GoogleDocsResourceUrlFormat = GoogleDocsFeedUrl + "/{0}"; + public const string GoogleDocsContentsUrlFormat = GoogleDocsResourceUrlFormat + "/contents"; + public const string GoogleDocsBatchUrl = GoogleDocsFeedUrl + "/batch"; + + //Google Docs rss feed namespaces + public const string AtomNamespace = "http://www.w3.org/2005/Atom"; + public const string GdNamespace = "http://schemas.google.com/g/2005"; + public const string BatchNamespace = "http://schemas.google.com/gdata/batch"; + + //Google Docs schemas + public const string SchemeParent = "http://schemas.google.com/docs/2007#parent"; + public const string SchemeKind = "http://schemas.google.com/g/2005#kind"; + public const string SchemeFolder = "http://schemas.google.com/docs/2007#folder"; + public const string SchemeResCreateMedia = "http://schemas.google.com/g/2005#resumable-create-media"; + public const string SchemeResEditMedia = "http://schemas.google.com/g/2005#resumable-edit-media"; + + public const string RootFolderId = "folder_root"; + public const string RootResCreateMediaUrl = "https://drive.google.com/feeds/upload/create-session/default/private/full/folder%3Aroot/contents"; + + public const string CallbackDefaultUrl = "http://sharpbox.codeplex.com"; + + public const string ResourceIdRegexPattern = @"^(document|drawing|file|folder|pdf|presentation|spreadsheet)_[-\w]+$"; + + public const int UploadChunkLength = 524288; + + //OAuth 1.0 + public const string OAuthGetRequestUrl = "https://www.google.com/accounts/OAuthGetRequestToken"; + public const string OAuthAuthorizeUrl = "https://www.google.com/accounts/OAuthAuthorizeToken"; + public const string OAuthGetAccessUrl = "https://www.google.com/accounts/OAuthGetAccessToken"; + public const string BasicScopeUrl = "https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/ https://docs.googleusercontent.com/"; + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsRequestToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsRequestToken.cs new file mode 100644 index 0000000000..b72fd5cbb6 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsRequestToken.cs @@ -0,0 +1,14 @@ +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + public class GoogleDocsRequestToken : ICloudStorageAccessToken + { + internal OAuthToken RealToken { get; private set; } + + internal GoogleDocsRequestToken(OAuthToken realToken) + { + RealToken = realToken; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsResourceHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsResourceHelper.cs new file mode 100644 index 0000000000..c9fbba2c25 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsResourceHelper.cs @@ -0,0 +1,77 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + internal static class GoogleDocsResourceHelper + { + public static bool IsFileEntry(ICloudFileSystemEntry entry) + { + return !(entry is ICloudDirectoryEntry); + } + + public static bool IsRootName(string name) + { + return name.Equals("/") || name.Equals(GoogleDocsConstants.RootFolderId); + } + + public static bool IsNoolOrRoot(ICloudFileSystemEntry dir) + { + return dir == null || ((dir is ICloudDirectoryEntry) && dir.Id.Equals(GoogleDocsConstants.RootFolderId)); + } + + public static void UpdateResourceByXml(IStorageProviderSession session, out ICloudFileSystemEntry resource, string xml) + { + var parsed = GoogleDocsXmlParser.ParseEntriesXml(session, xml).Single(); + resource = parsed; + } + + public static string GetStreamExtensionByKind(string kind) + { + switch (kind) + { + case "document": + return "docx"; + case "presentation": + return "pptx"; + case "spreadsheet": + return "xlsx"; + case "drawing": + return "svg"; + default: + return string.Empty; + } + } + + public static string GetExtensionByKind(string kind) + { + switch (kind) + { + case "document": + return "gdoc"; + case "presentation": + return "gslides"; + case "spreadsheet": + return "gsheet"; + case "drawing": + return "svg"; + default: + return string.Empty; + } + } + + public static bool IsResorceId(string name) + { + return Regex.IsMatch(name, GoogleDocsConstants.ResourceIdRegexPattern); + } + + public static bool OfGoogleDocsKind(ICloudFileSystemEntry entry) + { + var kind = entry.GetPropertyValue(GoogleDocsConstants.KindProperty); + return kind.Equals("document") || kind.Equals("presentation") || kind.Equals("spreadsheet") || kind.Equals("drawing"); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsStorageProvider.cs new file mode 100644 index 0000000000..595923d248 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsStorageProvider.cs @@ -0,0 +1,51 @@ +using System; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + public class GoogleDocsStorageProvider : GenericStorageProvider + { + public GoogleDocsStorageProvider() + : base(new CachedServiceWrapper(new GoogleDocsStorageProviderService())) + { + } + + public override Uri GetFileSystemObjectUrl(string path, ICloudDirectoryEntry parent) + { + var ph = new PathHelper(path); + var elements = ph.GetPathElements(); + var current = parent; + + for (var i = 0; i < elements.Length; i++) + { + var child = current.GetChild(elements[i], false); + if (i == elements.Length - 1) + { + if (child == null || child is ICloudDirectoryEntry) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + } + + return new Uri(child.GetPropertyValue(GoogleDocsConstants.DownloadUrlProperty)); + } + + if (child == null || !(child is ICloudDirectoryEntry)) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + } + + current = (ICloudDirectoryEntry)child; + } + + return null; + } + + public override ICloudDirectoryEntry CreateFolder(string name, ICloudDirectoryEntry parent) + { + if (parent == null) parent = GetRoot(); + return Service.CreateResource(Session, name, parent) as ICloudDirectoryEntry; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsToken.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsToken.cs new file mode 100644 index 0000000000..539fcc8225 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/GoogleDocsToken.cs @@ -0,0 +1,28 @@ +using System; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs +{ + internal class GoogleDocsToken : OAuthToken, ICloudStorageAccessToken + { + public string ConsumerKey { get; private set; } + public string ConsumerSecret { get; private set; } + + public GoogleDocsToken(OAuthToken token, string consumerKey, string consumerSecret) + : this(token.TokenKey, token.TokenSecret, consumerKey, consumerSecret) + { + } + + public GoogleDocsToken(string tokenKey, string tokenSecret, string consumerKey, string consumerSecret) + : base(tokenKey, tokenSecret) + { + ConsumerKey = consumerKey; + ConsumerSecret = consumerSecret; + } + + public override string ToString() + { + return string.Format("{0}+{1}", TokenKey, TokenSecret); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderService.cs new file mode 100644 index 0000000000..1c646b145e --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderService.cs @@ -0,0 +1,649 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using AppLimit.CloudComputing.SharpBox.Common.Extensions; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Token; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic +{ + internal class GoogleDocsStorageProviderService : GenericStorageProviderService + { + public enum RemoveMode + { + Trash, + Delete, + FromParentCollection + }; + + #region GoogleDocs Specific + + public void RefreshDirectoryContent(IStorageProviderSession session, BaseDirectoryEntry entry) + { + if (entry == null) + return; + + var url = string.Format(GoogleDocsConstants.GoogleDocsContentsUrlFormat, entry.Id.ReplaceFirst("_", "%3a")); + var parameters = new Dictionary { { "max-results", "1000" } }; + try + { + while (!string.IsNullOrEmpty(url)) + { + var request = CreateWebRequest(session, url, "GET", parameters); + using (var response = (HttpWebResponse)request.GetResponse()) + using (var rs = response.GetResponseStream()) + using (var streamReader = new StreamReader(rs)) + { + var feedXml = streamReader.ReadToEnd(); + var childs = GoogleDocsXmlParser.ParseEntriesXml(session, feedXml); + entry.AddChilds(childs); + + url = GoogleDocsXmlParser.ParseNext(feedXml); + } + } + } + catch (WebException) + { + } + } + + public bool RemoveResource(IStorageProviderSession session, ICloudFileSystemEntry resource, RemoveMode mode) + { + string url; + Dictionary parameters = null; + + if (mode == RemoveMode.FromParentCollection) + { + var pId = (resource.Parent != null ? resource.Parent.Id : GoogleDocsConstants.RootFolderId).ReplaceFirst("_", "%3a"); + url = string.Format("{0}/{1}/contents/{2}", GoogleDocsConstants.GoogleDocsFeedUrl, pId, resource.Id.ReplaceFirst("_", "%3a")); + } + else + { + url = string.Format(GoogleDocsConstants.GoogleDocsResourceUrlFormat, resource.Id.ReplaceFirst("_", "%3a")); + parameters = new Dictionary { { "delete", "true" } }; + } + + var request = CreateWebRequest(session, url, "DELETE", parameters); + request.Headers.Add("If-Match", "*"); + + try + { + using (var response = (HttpWebResponse)request.GetResponse()) + if (response.StatusCode == HttpStatusCode.OK) + return true; + } + catch (WebException) + { + } + + return false; + } + + public bool AddToCollection(IStorageProviderSession session, ICloudFileSystemEntry resource, ICloudDirectoryEntry collection) + { + var url = string.Format(GoogleDocsConstants.GoogleDocsContentsUrlFormat, collection.Id.ReplaceFirst("_", "%3a")); + var request = CreateWebRequest(session, url, "POST", null); + GoogleDocsXmlParser.WriteAtom(request, GoogleDocsXmlParser.EntryElement(null, GoogleDocsXmlParser.IdElement(resource.Id.ReplaceFirst("_", "%3a")))); + + try + { + var response = (HttpWebResponse)request.GetResponse(); + if (response.StatusCode == HttpStatusCode.Created) + return true; + } + catch (WebException) + { + } + + return false; + } + + #endregion + + #region GenericStorageProviderService members + + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return token is GoogleDocsToken; + } + + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + var gdToken = token as GoogleDocsToken; + return new GoogleDocsStorageProviderSession(this, + configuration, + new OAuthConsumerContext(gdToken.ConsumerKey, gdToken.ConsumerSecret), + gdToken); + } + + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + if (GoogleDocsResourceHelper.IsNoolOrRoot(parent) && GoogleDocsResourceHelper.IsRootName(name)) + { + var root = new BaseDirectoryEntry("/", 0, DateTime.Now, session.Service, session) { Id = GoogleDocsConstants.RootFolderId }; + root.SetPropertyValue(GoogleDocsConstants.ResCreateMediaProperty, GoogleDocsConstants.RootResCreateMediaUrl); + RefreshDirectoryContent(session, root); + return root; + } + + if (name.Equals("/")) + { + RefreshDirectoryContent(session, parent as BaseDirectoryEntry); + } + + if (GoogleDocsResourceHelper.IsResorceId(name)) + { + var url = string.Format(GoogleDocsConstants.GoogleDocsResourceUrlFormat, name.ReplaceFirst("_", "%3a")); + var request = CreateWebRequest(session, url, "GET", null); + try + { + string xml; + using (var response = (HttpWebResponse)request.GetResponse()) + using (var rs = response.GetResponseStream()) + using (var streamReader = new StreamReader(rs)) + { + xml = streamReader.ReadToEnd(); + } + var entry = GoogleDocsXmlParser.ParseEntriesXml(session, xml).FirstOrDefault(); + + if (entry == null) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + + if (parent != null) + (parent as BaseDirectoryEntry).AddChild(entry); + + var dirEntry = entry as BaseDirectoryEntry; + + if (dirEntry == null) + return entry; + + RefreshDirectoryContent(session, dirEntry); + return dirEntry; + } + catch (WebException) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound); + } + } + + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + if (resource == null) + return; + + if (resource.Id.Equals(GoogleDocsConstants.RootFolderId)) + { + RefreshDirectoryContent(session, resource as BaseDirectoryEntry); + return; + } + + var resourceUrl = string.Format(GoogleDocsConstants.GoogleDocsResourceUrlFormat, resource.Id.ReplaceFirst("_", "%3a")); + var request = CreateWebRequest(session, resourceUrl, "GET", null); + request.Headers.Add("If-None-Match", resource.GetPropertyValue(GoogleDocsConstants.EtagProperty)); + + try + { + using (var response = (HttpWebResponse)request.GetResponse()) + { + if (response.StatusCode != HttpStatusCode.NotModified) + { + using (var s = response.GetResponseStream()) + using (var streamReader = new StreamReader(s)) + { + var xml = streamReader.ReadToEnd(); + + GoogleDocsResourceHelper.UpdateResourceByXml(session, out resource, xml); + } + } + } + + var dirEntry = resource as BaseDirectoryEntry; + + if (dirEntry == null || dirEntry.HasChildrens == nChildState.HasChilds) + return; + + RefreshDirectoryContent(session, dirEntry); + } + catch (WebException) + { + + } + } + + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentException("Name cannot be empty"); + } + + var url = GoogleDocsResourceHelper.IsNoolOrRoot(parent) + ? GoogleDocsConstants.GoogleDocsFeedUrl + : string.Format(GoogleDocsConstants.GoogleDocsContentsUrlFormat, parent.Id.ReplaceFirst("_", "%3a")); + + var request = CreateWebRequest(session, url, "POST", null); + GoogleDocsXmlParser.WriteAtom(request, GoogleDocsXmlParser.EntryElement(GoogleDocsXmlParser.CategoryElement(), GoogleDocsXmlParser.TitleElement(name))); + + try + { + using (var response = (HttpWebResponse)request.GetResponse()) + { + if (response.StatusCode == HttpStatusCode.Created) + { + using (var rs = response.GetResponseStream()) + using (var streamReader = new StreamReader(rs)) + { + var xml = streamReader.ReadToEnd(); + var entry = GoogleDocsXmlParser.ParseEntriesXml(session, xml).First(); + + if (parent != null) + (parent as BaseDirectoryEntry).AddChild(entry); + + return entry; + } + } + } + } + catch (WebException) + { + throw new SharpBoxException(SharpBoxErrorCodes.ErrorCreateOperationFailed); + } + + return null; + } + + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + if (string.IsNullOrEmpty(newName) || GoogleDocsResourceHelper.IsNoolOrRoot(fsentry)) + return false; + + var url = string.Format(GoogleDocsConstants.GoogleDocsResourceUrlFormat, fsentry.Id.ReplaceFirst("_", "%3a")); + + var request = CreateWebRequest(session, url, "PUT", null); + request.Headers.Add("If-Match", fsentry.GetPropertyValue(GoogleDocsConstants.EtagProperty)); + GoogleDocsXmlParser.WriteAtom(request, GoogleDocsXmlParser.EntryElement(GoogleDocsXmlParser.TitleElement(newName))); + + try + { + var response = (HttpWebResponse)request.GetResponse(); + if (response.StatusCode == HttpStatusCode.OK) + { + //check if extension added + if (!(fsentry is ICloudDirectoryEntry) && string.IsNullOrEmpty(Path.GetExtension(newName))) + newName = newName + Path.GetExtension(fsentry.Name); + (fsentry as BaseFileEntry).Name = newName; + return true; + } + } + catch (WebException) + { + } + + return false; + } + + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + if (GoogleDocsResourceHelper.IsNoolOrRoot(entry)) + return false; + + if (RemoveResource(session, entry, RemoveMode.Delete)) + { + var parent = entry.Parent as BaseDirectoryEntry; + if (parent != null) + parent.RemoveChildById(entry.Id); + + return true; + } + + return false; + } + + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + if (fsentry == null || newParent == null || GoogleDocsResourceHelper.IsNoolOrRoot(fsentry)) + return false; + + if (RemoveResource(session, fsentry, RemoveMode.FromParentCollection) && AddToCollection(session, fsentry, newParent)) + { + if (fsentry.Parent != null) + (fsentry.Parent as BaseDirectoryEntry).RemoveChild(fsentry as BaseFileEntry); + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + + return true; + } + + return false; + } + + public override bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + if (AddToCollection(session, fsentry, newParent)) + { + (newParent as BaseDirectoryEntry).AddChild(fsentry as BaseFileEntry); + return true; + } + return false; + } + + public override string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry entry, string path) + { + if (!string.IsNullOrEmpty(path)) + { + var id = path; + var index = id.LastIndexOf("/"); + if (index != -1) + { + id = id.Substring(index + 1); + } + if (GoogleDocsResourceHelper.IsResorceId(id)) + { + return id; + } + } + else if (entry != null) + { + return entry.Id; + } + return base.GetResourceUrl(session, null, path); + } + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + var url = fileSystemEntry.GetPropertyValue(GoogleDocsConstants.DownloadUrlProperty); + + var format = GoogleDocsResourceHelper.GetStreamExtensionByKind(fileSystemEntry.GetPropertyValue(GoogleDocsConstants.KindProperty)); + if (!string.IsNullOrEmpty(format)) + { + url = string.Format("{0}&exportFormat={1}", url, format); + if (format.Equals("docx")) + url += "&format=" + format; + } + + var request = CreateWebRequest(session, url, "GET", null, true); + var response = (HttpWebResponse)request.GetResponse(); + + if (fileSystemEntry.Length > 0) + { + return new BaseFileEntryDownloadStream(response.GetResponseStream(), fileSystemEntry); + } + + var isChukedEncoding = string.Equals(response.Headers.Get("Transfer-Encoding"), "Chunked", StringComparison.OrdinalIgnoreCase); + if (!isChukedEncoding) + { + ((BaseFileEntry)fileSystemEntry).Length = response.ContentLength; + return new BaseFileEntryDownloadStream(response.GetResponseStream(), fileSystemEntry); + } + + var tempBuffer = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 8096, FileOptions.DeleteOnClose); + using (var stream = response.GetResponseStream()) + { + stream.CopyTo(tempBuffer); + } + tempBuffer.Flush(); + tempBuffer.Seek(0, SeekOrigin.Begin); + return tempBuffer; + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + var tempStream = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose); + var stream = new WebRequestStream(tempStream, null, null); + stream.PushPreDisposeOperation(CommitUploadOperation, session, fileSystemEntry, tempStream, uploadSize); + return stream; + } + + public override bool SupportsDirectRetrieve + { + get { return false; } + } + + private void CommitUploadOperation(object[] args) + { + var session = (IStorageProviderSession)args[0]; + var file = (BaseFileEntry)args[1]; + var stream = (Stream)args[2]; + var contentLength = (long)args[3]; + + stream.Flush(); + stream.Seek(0, SeekOrigin.Begin); + + var uploadSession = CreateUploadSession(session, file, contentLength); + UploadChunk(session, uploadSession, stream, contentLength); + } + + #region resumable uploads + + public override bool SupportsChunking + { + get { return true; } + } + + public override IResumableUploadSession CreateUploadSession(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long bytesToTransfer) + { + WebRequest request; + if (GoogleDocsResourceHelper.IsResorceId(fileSystemEntry.Id)) + { + //request for update + request = CreateWebRequest(session, fileSystemEntry.GetPropertyValue(GoogleDocsConstants.ResEditMediaProperty), "PUT", null, true); + request.Headers.Add("If-Match", "*"); + } + else + { + //request for create + request = CreateWebRequest(session, fileSystemEntry.Parent.GetPropertyValue(GoogleDocsConstants.ResCreateMediaProperty) + "?convert=false", "POST", null, true); + } + + if (GoogleDocsResourceHelper.OfGoogleDocsKind(fileSystemEntry)) + { + ((BaseFileEntry)fileSystemEntry).Name = Path.GetFileNameWithoutExtension(fileSystemEntry.Name); + } + + GoogleDocsXmlParser.WriteAtom(request, GoogleDocsXmlParser.EntryElement(GoogleDocsXmlParser.TitleElement(fileSystemEntry.Name))); + request.Headers.Add("X-Upload-Content-Type", Common.Net.MimeMapping.GetMimeMapping(fileSystemEntry.Name)); + request.Headers.Add("X-Upload-Content-Length", bytesToTransfer.ToString(CultureInfo.InvariantCulture)); + + + var response = request.GetResponse(); + + var uploadSession = new ResumableUploadSession(fileSystemEntry, bytesToTransfer); + uploadSession["Location"] = response.Headers["Location"]; + uploadSession.Status = ResumableUploadSessionStatus.Started; + + return uploadSession; + } + + public override void AbortUploadSession(IStorageProviderSession session, IResumableUploadSession uploadSession) + { + if (uploadSession.Status != ResumableUploadSessionStatus.Completed) + { + ((ResumableUploadSession)uploadSession).Status = ResumableUploadSessionStatus.Aborted; + } + } + + public override void UploadChunk(IStorageProviderSession session, IResumableUploadSession uploadSession, Stream stream, long chunkLength) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (uploadSession.Status != ResumableUploadSessionStatus.Started) + throw new InvalidOperationException("Can't upload chunk for given upload session."); + + var request = WebRequest.Create(uploadSession.GetItem("Location")); + request.Method = "PUT"; + request.ContentLength = chunkLength; + request.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", + uploadSession.BytesTransfered, + uploadSession.BytesTransfered + chunkLength - 1, + uploadSession.BytesToTransfer)); + + using (var requestStream = request.GetRequestStream()) + { + stream.CopyTo(requestStream); + } + + HttpWebResponse response; + try + { + response = (HttpWebResponse)request.GetResponse(); + } + catch (WebException exception) + { + if (exception.Status == WebExceptionStatus.ProtocolError && exception.Response != null && exception.Response.Headers.AllKeys.Contains("Range")) + { + response = (HttpWebResponse)exception.Response; + } + else + { + throw; + } + } + + if (response.StatusCode != HttpStatusCode.Created) + { + var uplSession = (ResumableUploadSession)uploadSession; + uplSession.BytesTransfered += chunkLength; + + var locationHeader = response.Headers["Location"]; + if (!string.IsNullOrEmpty(locationHeader)) + { + uplSession["Location"] = locationHeader; + } + } + else + { + ((ResumableUploadSession)uploadSession).Status = ResumableUploadSessionStatus.Completed; + + using (var responseStream = response.GetResponseStream()) + { + if (responseStream == null) return; + string xml; + using (var streamReader = new StreamReader(responseStream)) + { + xml = streamReader.ReadToEnd(); + } + var respFile = GoogleDocsXmlParser.ParseEntriesXml(session, xml).First(); + var initFile = (BaseFileEntry)uploadSession.File; + + //replace old file with the file from response + initFile.Name = respFile.Name; + initFile.Id = respFile.Id; + initFile.Length = respFile.Length; + initFile.Modified = respFile.Modified; + initFile[GoogleDocsConstants.EtagProperty] = respFile[GoogleDocsConstants.EtagProperty]; + initFile[GoogleDocsConstants.KindProperty] = respFile[GoogleDocsConstants.KindProperty]; + initFile[GoogleDocsConstants.DownloadUrlProperty] = respFile[GoogleDocsConstants.DownloadUrlProperty]; + initFile[GoogleDocsConstants.ResEditMediaProperty] = respFile[GoogleDocsConstants.ResEditMediaProperty]; + + var parent = initFile.Parent as BaseDirectoryEntry; + if (parent != null) + { + parent.RemoveChildById(initFile.Name); + parent.AddChild(initFile); + } + } + } + + response.Close(); + } + + #endregion + + #endregion + + #region oAuth + + public override void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token) + { + if (token is GoogleDocsRequestToken) + { + var requestToken = token as GoogleDocsRequestToken; + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsAppKey, requestToken.RealToken.TokenKey); + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsAppSecret, requestToken.RealToken.TokenSecret); + } + else if (token is GoogleDocsToken) + { + var gdtoken = token as GoogleDocsToken; + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsAppKey, gdtoken.ConsumerKey); + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsAppSecret, gdtoken.ConsumerSecret); + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsUsername, gdtoken.TokenKey); + tokendata.Add(GoogleDocsConstants.TokenGoogleDocsPassword, gdtoken.TokenSecret); + } + } + + public override ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + var type = tokendata[CloudStorage.TokenCredentialType]; + + if (type.Equals(typeof (GoogleDocsToken).ToString())) + { + var tokenKey = tokendata[GoogleDocsConstants.TokenGoogleDocsUsername]; + var tokenSecret = tokendata[GoogleDocsConstants.TokenGoogleDocsPassword]; + var consumerKey = tokendata[GoogleDocsConstants.TokenGoogleDocsAppKey]; + var consumerSecret = tokendata[GoogleDocsConstants.TokenGoogleDocsAppSecret]; + + return new GoogleDocsToken(tokenKey, tokenSecret, consumerKey, consumerSecret); + } + + if (type.Equals(typeof (GoogleDocsRequestToken).ToString())) + { + var tokenKey = tokendata[GoogleDocsConstants.TokenGoogleDocsAppKey]; + var tokenSecret = tokendata[GoogleDocsConstants.TokenGoogleDocsAppSecret]; + + return new GoogleDocsRequestToken(new OAuthToken(tokenKey, tokenSecret)); + } + + throw new InvalidCastException("Token type not supported through this provider"); + } + + #endregion + + #region Helpers + + private static WebRequest CreateWebRequest(IStorageProviderSession storageProviderSession, string url, string method, Dictionary parameters, bool oAuthParamsAsHeader = false) + { + var session = storageProviderSession as GoogleDocsStorageProviderSession; + var configuration = session.ServiceConfiguration as GoogleDocsConfiguration; + WebRequest request; + if (!oAuthParamsAsHeader) + { + request = OAuthService.CreateWebRequest(url, method, null, null, session.Context, (GoogleDocsToken)session.SessionToken, parameters); + } + else + { + request = WebRequest.Create(url); + request.Method = method; + + String oAuthHeader = OAuthService.GetOAuthAuthorizationHeader(url, session.Context, (GoogleDocsToken)session.SessionToken, null, method); + request.Headers.Add("Authorization", oAuthHeader); + } + + //using API's 3.0 version + request.Headers.Add("GData-Version", configuration.GDataVersion); + + return request; + } + + private static OAuthService OAuthService + { + get { return new OAuthService(); } + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderSession.cs new file mode 100644 index 0000000000..9bba6907db --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsStorageProviderSession.cs @@ -0,0 +1,24 @@ +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth.Context; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic +{ + internal class GoogleDocsStorageProviderSession : IStorageProviderSession + { + public GoogleDocsStorageProviderSession(IStorageProviderService service, ICloudStorageConfiguration configuration, OAuthConsumerContext context, ICloudStorageAccessToken token) + { + Service = service; + ServiceConfiguration = configuration; + Context = context; + SessionToken = token; + } + + public OAuthConsumerContext Context { get; private set; } + + public ICloudStorageAccessToken SessionToken { get; private set; } + + public IStorageProviderService Service { get; private set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; private set; } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsXmlParser.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsXmlParser.cs new file mode 100644 index 0000000000..7ed7d53242 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/GoogleDocs/Logic/GoogleDocsXmlParser.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Xml.Linq; +using AppLimit.CloudComputing.SharpBox.Common.Extensions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.GoogleDocs.Logic +{ + internal static class GoogleDocsXmlParser + { + public static IEnumerable ParseEntriesXml(IStorageProviderSession session, string xml) + { + var doc = XDocument.Load(new StringReader(xml)); + + var entries = doc.Descendants(XName.Get("entry", GoogleDocsConstants.AtomNamespace)); + + var fsEntries = new List(); + + foreach (var entry in entries) + { + var resourceId = entry.Element(XName.Get("resourceId", GoogleDocsConstants.GdNamespace)).ValueOrEmpty().Replace(':', '_'); + var title = entry.Element(XName.Get("title", GoogleDocsConstants.AtomNamespace)).ValueOrEmpty(); + var updated = entry.Element(XName.Get("updated", GoogleDocsConstants.AtomNamespace)).ValueOrEmpty(); + var etag = entry.Attribute(XName.Get("etag", GoogleDocsConstants.GdNamespace)).ValueOrEmpty(); + var kind = entry.Elements(XName.Get("category", GoogleDocsConstants.AtomNamespace)).Single(x => x.Attribute("scheme").ValueOrEmpty().Equals(GoogleDocsConstants.SchemeKind)).Attribute("label").ValueOrEmpty(); + + BaseFileEntry fsEntry = kind.Equals("folder") + ? new BaseDirectoryEntry(title, 0, Convert.ToDateTime(updated).ToUniversalTime(), session.Service, session) + : new BaseFileEntry(title, 0, Convert.ToDateTime(updated).ToUniversalTime(), session.Service, session); + + fsEntry.Id = resourceId; + fsEntry.SetPropertyValue(GoogleDocsConstants.EtagProperty, etag); + fsEntry.SetPropertyValue(GoogleDocsConstants.KindProperty, kind); + if (kind.Equals("folder")) + { + var uploadUrl = entry.Elements(XName.Get("link", GoogleDocsConstants.AtomNamespace)).FirstOrDefault(x => x.Attribute("rel").ValueOrEmpty().Equals(GoogleDocsConstants.SchemeResCreateMedia)).AttributeOrNull("href").ValueOrEmpty(); + fsEntry.SetPropertyValue(GoogleDocsConstants.ResCreateMediaProperty, uploadUrl); + } + else + { + var length = entry.Element(XName.Get("quotaBytesUsed", GoogleDocsConstants.GdNamespace)).ValueOrEmpty(); + var downloadUrl = entry.Elements(XName.Get("content", GoogleDocsConstants.AtomNamespace)).FirstOrDefault().AttributeOrNull("src").ValueOrEmpty(); + var editUrl = entry.Elements(XName.Get("link", GoogleDocsConstants.AtomNamespace)).FirstOrDefault(x => x.Attribute("rel").ValueOrEmpty().Equals(GoogleDocsConstants.SchemeResEditMedia)).AttributeOrNull("href").ValueOrEmpty(); + + fsEntry.Length = Convert.ToInt64(length); + fsEntry.SetPropertyValue(GoogleDocsConstants.DownloadUrlProperty, downloadUrl); + if (!string.IsNullOrEmpty(editUrl)) + fsEntry.SetPropertyValue(GoogleDocsConstants.ResEditMediaProperty, editUrl); + + var ext = GoogleDocsResourceHelper.GetExtensionByKind(kind); + if (!string.IsNullOrEmpty(ext)) + { + fsEntry.Name += '.' + ext; + } + } + + //var parents = entry.Elements(XName.Get("link", GoogleDocsConstants.AtomNamespace)) + // .Where(x => x.AttributeOrNull("rel").ValueOrEmpty().Equals(GoogleDocsConstants.SchemeParent)) + // .Select(x => + // { + // var parentUrl = x.ValueOrEmpty(); + // var index = parentUrl.LastIndexOf('/'); + // return parentUrl.Substring(index).Replace(':', '_').Replace("%3A", "_"); + // }); + + //fsEntry.SetPropertyValue(GoogleDocsConstants.ParentsProperty, String.Join(",", parents.ToArray())); + + fsEntries.Add(fsEntry); + } + + return fsEntries; + } + + public static string ParseNext(string xml) + { + var doc = XDocument.Load(new StringReader(xml)); + return doc.Elements(XName.Get("link", GoogleDocsConstants.AtomNamespace)) + .SingleOrDefault(x => x.AttributeOrNull("rel").ValueOrEmpty().Equals("next")).ValueOrEmpty(); + } + + public static void WriteAtom(WebRequest request, params object[] content) + { + var xmlDoc = new XDocument { Declaration = new XDeclaration("1.0", "UTF-8", null) }; + xmlDoc.Add(content.Length > 1 ? new XElement(XName.Get("feed", GoogleDocsConstants.AtomNamespace), content) : content[0]); + + var sb = new StringBuilder(); + var tr = new StringWriter(sb); + xmlDoc.Save(tr); + + var atom = sb.ToString(); + + var bytes = Encoding.UTF8.GetBytes(atom); + + request.ContentLength = bytes.Length; + request.ContentType = "application/atom+xml"; + + var stream = request.GetRequestStream(); + stream.Write(bytes, 0, bytes.Length); + stream.Close(); + } + + public static XElement EntryElement(params object[] content) + { + return EntryElement(null, content); + } + + public static XElement EntryElement(string etag, params object[] content) + { + var entry = new XElement(XName.Get("entry", GoogleDocsConstants.AtomNamespace), content); + if (!string.IsNullOrEmpty(etag)) + entry.SetAttributeValue(XName.Get("etag", GoogleDocsConstants.GdNamespace), etag); + return entry; + } + + public static XElement OperationElement(string type) + { + return new XElement(XName.Get("operation", GoogleDocsConstants.BatchNamespace), new XAttribute("type", type)); + } + + public static XElement CategoryElement() + { + return new XElement(XName.Get("category", GoogleDocsConstants.AtomNamespace), + new XAttribute("scheme", GoogleDocsConstants.SchemeKind), + new XAttribute("term", GoogleDocsConstants.SchemeFolder)); + } + + public static XElement TitleElement(string title) + { + return new XElement(XName.Get("title", GoogleDocsConstants.AtomNamespace), title); + } + + public static XElement IdElement(string id) + { + return new XElement(XName.Get("id", GoogleDocsConstants.AtomNamespace), GoogleDocsConstants.GoogleDocsFeedUrl + '/' + id); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Authorization/SkyDriveAuthorizationHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Authorization/SkyDriveAuthorizationHelper.cs new file mode 100644 index 0000000000..904e04019f --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Authorization/SkyDriveAuthorizationHelper.cs @@ -0,0 +1,135 @@ +using System; +using System.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Authorization +{ + /// + /// Functions for requesting, refresh and maintain the access tokens for SkyDrive + /// + public static class SkyDriveAuthorizationHelper + { + /// + /// Build uri string to obtain the authorization code + /// + /// ID of your app + /// Uri string + public static string BuildAuthCodeUrl(string clientID) + { + return BuildAuthCodeUrl(clientID, null); + } + + /// + /// Build uri string to obtain the authorization code + /// + /// ID of your app + /// Scopes to which you want to get the access + /// Uri string + public static string BuildAuthCodeUrl(string clientID, string scopes) + { + return BuildAuthCodeUrl(clientID, scopes, null); + } + + /// + /// Build uri string to obtain the authorization code + /// + /// ID of your app + /// Scopes to which you want to get the access + /// Page to which you will be redirect with the authorization obtained code + /// Uri string + public static string BuildAuthCodeUrl(string clientID, string scopes, string redirectUri) + { + if (string.IsNullOrEmpty(clientID)) + throw new ArgumentNullException("clientID"); + + if (string.IsNullOrEmpty(scopes)) + scopes = SkyDriveConstants.DefaultScopes; + + if (string.IsNullOrEmpty(redirectUri)) + redirectUri = SkyDriveConstants.DefaultRedirectUri; + + return string.Format("{0}?client_id={1}&scope={2}&response_type=code&redirect_uri={3}", + SkyDriveConstants.OAuth20AuthUrl, HttpUtility.UrlEncode(clientID), + HttpUtility.UrlEncode(scopes), redirectUri); + } + + /// + /// Exchange your authorization code for a valid access token + /// + /// ID of your app + /// Secret of your app + /// Authorization code + /// Access token + public static ICloudStorageAccessToken GetAccessToken(string clientID, string clientSecret, string authCode) + { + return GetAccessToken(clientID, clientSecret, null, authCode); + } + + /// + /// Exchange your authorization code for a valid access token + /// + /// ID of your app + /// Secret of your app + /// Redirect uri you used to obtained authorization code. Serves as request validator + /// Authorization code + /// Access token + public static ICloudStorageAccessToken GetAccessToken(string clientID, string clientSecret, string redirectUri, string authCode) + { + if (string.IsNullOrEmpty(clientID)) throw new ArgumentNullException("clientID"); + if (string.IsNullOrEmpty(clientSecret)) throw new ArgumentNullException("clientSecret"); + if (string.IsNullOrEmpty(authCode)) throw new ArgumentNullException("authCode"); + + if (string.IsNullOrEmpty(redirectUri)) + redirectUri = SkyDriveConstants.DefaultRedirectUri; + + var query = string.Format("client_id={0}&redirect_uri={1}&client_secret={2}&code={3}&grant_type=authorization_code", + clientID, redirectUri, clientSecret, authCode); + + var json = SkyDriveRequestHelper.PerformRequest(SkyDriveConstants.OAuth20TokenUrl, "application/x-www-form-urlencoded", "POST", query, 2); + if (json != null) + { + var token = OAuth20Token.FromJson(json); + token.ClientID = clientID; + token.ClientSecret = clientSecret; + token.RedirectUri = redirectUri; + token.Timestamp = DateTime.UtcNow; + return token; + } + + return null; + } + + /// + /// Refresh expired access token + /// + /// Access token + /// Refreshed access token + public static ICloudStorageAccessToken RefreshToken(ICloudStorageAccessToken token) + { + var sdToken = token as OAuth20Token; + if (sdToken == null || !CanRefresh(sdToken)) + throw new ArgumentException("Can not refresh given token", "token"); + + var query = string.Format("client_id={0}&client_secret={1}&redirect_uri={2}&grant_type=refresh_token&refresh_token={3}", + sdToken.ClientID, sdToken.ClientSecret, sdToken.RedirectUri, sdToken.RefreshToken); + + var json = SkyDriveRequestHelper.PerformRequest(SkyDriveConstants.OAuth20TokenUrl, "application/x-www-form-urlencoded", "POST", query, 2); + if (json != null) + { + var refreshed = OAuth20Token.FromJson(json); + refreshed.ClientID = sdToken.ClientID; + refreshed.ClientSecret = sdToken.ClientSecret; + refreshed.RedirectUri = sdToken.RedirectUri; + refreshed.Timestamp = DateTime.UtcNow; + return refreshed; + } + + return token; + } + + private static bool CanRefresh(OAuth20Token token) + { + return !string.IsNullOrEmpty(token.ClientID) && !string.IsNullOrEmpty(token.ClientSecret) && !string.IsNullOrEmpty(token.RedirectUri); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProvider.cs new file mode 100644 index 0000000000..b62ea5d5d2 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProvider.cs @@ -0,0 +1,15 @@ +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Logic +{ + internal class SkyDriveStorageProvider : GenericStorageProvider + { + public SkyDriveStorageProvider() + : base(new CachedServiceWrapper(new SkyDriveStorageProviderService())) + { + } + + //public override string GetFileSystemObjectPath(ICloudFileSystemEntry fsObject) + //{ + // return "/" + fsObject.Id; + //} + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderService.cs new file mode 100644 index 0000000000..7e51641d6c --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderService.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; +using AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Authorization; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Logic +{ + internal class SkyDriveStorageProviderService : GenericStorageProviderService + { + public void RefreshDirectoryContent(IStorageProviderSession session, ICloudDirectoryEntry directory) + { + if (!(directory is BaseDirectoryEntry)) return; + var uri = string.Format(SkyDriveConstants.FilesAccessUrlFormat, directory.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + (directory as BaseDirectoryEntry).AddChilds(RequestContentByUrl(session, uri).Cast()); + } + + private static IEnumerable RequestContentByUrl(IStorageProviderSession session, string url) + { + var json = SkyDriveRequestHelper.PerformRequest(session, url); + return SkyDriveJsonParser.ParseListOfEntries(session, json) ?? new List(); + } + + private static ICloudFileSystemEntry RequestResourseByUrl(IStorageProviderSession session, string url) + { + var json = SkyDriveRequestHelper.PerformRequest(session, url); + return SkyDriveJsonParser.ParseSingleEntry(session, json); + } + + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return token is OAuth20Token; + } + + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + var skydriveToken = token as OAuth20Token; + if (skydriveToken == null) throw new ArgumentException("Cannot create skydrive session with given token", "token"); + if (skydriveToken.IsExpired) token = SkyDriveAuthorizationHelper.RefreshToken(skydriveToken); + return new SkyDriveStorageProviderSession(token, this, configuration); + } + + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + /* In this method name could be either requested resource name or it's ID. + * In first case just refresh the parent and then search child with an appropriate. + * In second case it does not matter if parent is null or not a parent because we use only resource ID. */ + + if (SkyDriveHelpers.HasResourceID(name) || name.Equals("/") && parent == null) + //If request by ID or root folder requested + { + var id = SkyDriveHelpers.GetResourceID(name); + var uri = id != string.Empty + ? string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, id) + : SkyDriveConstants.RootAccessUrl; + + if (SkyDriveHelpers.IsFolderID(id)) + { + var contents = new List(); + + /*var completeContent = new AutoResetEvent(false); + ThreadPool.QueueUserWorkItem(state => + { + contents.AddRange(RequestContentByUrl(session, uri + "/files")); + ((AutoResetEvent) state).Set(); + }, completeContent); + + var completeEntry = new AutoResetEvent(false); + ThreadPool.QueueUserWorkItem(state => + { + entry = RequestResourseByUrl(session, uri) as BaseDirectoryEntry; + ((AutoResetEvent) state).Set(); + }, completeEntry); + + WaitHandle.WaitAll(new WaitHandle[] {completeContent, completeEntry});*/ + + var entry = RequestResourseByUrl(session, uri) as BaseDirectoryEntry; + contents.AddRange(RequestContentByUrl(session, uri + "/files")); + + if (entry != null && contents.Any()) + entry.AddChilds(contents.Cast()); + + return entry; + } + + return RequestResourseByUrl(session, uri); + } + else + { + string uri; + if (SkyDriveHelpers.HasParentID(name)) + uri = string.Format(SkyDriveConstants.FilesAccessUrlFormat, SkyDriveHelpers.GetParentID(name)); + else if (parent != null) + uri = string.Format(SkyDriveConstants.FilesAccessUrlFormat, parent.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + else + uri = SkyDriveConstants.RootAccessUrl + "/files"; + + name = Path.GetFileName(name); + var entry = RequestContentByUrl(session, uri).FirstOrDefault(x => x.Name.Equals(name)); + return entry; + } + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + //not refresh if resource was requested recently + var timestamp = resource.GetPropertyValue(SkyDriveConstants.TimestampKey); + var refreshNeeded = DateTime.Parse(timestamp, CultureInfo.InvariantCulture) + TimeSpan.FromSeconds(5) < DateTime.UtcNow; + if (refreshNeeded) + { + //Request resource by ID and then update properties from requested + var current = RequestResource(session, resource.GetPropertyValue(SkyDriveConstants.InnerIDKey), null); + SkyDriveHelpers.CopyProperties(current, resource); + } + + var directory = resource as ICloudDirectoryEntry; + if (directory != null && !refreshNeeded && directory.HasChildrens == nChildState.HasNotEvaluated) + RefreshDirectoryContent(session, directory); + } + + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + var uri = string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var json = SkyDriveRequestHelper.PerformRequest(session, uri, "DELETE", null, true); + + if (!SkyDriveJsonParser.ContainsError(json, false)) + { + var parent = entry.Parent as BaseDirectoryEntry; + if (parent != null) + parent.RemoveChildById(entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + return true; + } + + return false; + } + + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + if (name.Contains("/")) + throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidFileOrDirectoryName); + + var uri = + parent != null + ? string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, parent.GetPropertyValue(SkyDriveConstants.InnerIDKey)) + : SkyDriveConstants.RootAccessUrl; + + var data = string.Format("{{name: \"{0}\"}}", name); + var json = SkyDriveRequestHelper.PerformRequest(session, uri, "POST", data, false); + var entry = SkyDriveJsonParser.ParseSingleEntry(session, json); + + var parentBase = parent as BaseDirectoryEntry; + if (parentBase != null && entry != null) + parentBase.AddChild(entry as BaseFileEntry); + + return entry; + } + + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry entry, string newName) + { + if (entry.Name.Equals("/") || newName.Contains("/")) + return false; + + var uri = string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var data = string.Format("{{name: \"{0}\"}}", newName); + var json = SkyDriveRequestHelper.PerformRequest(session, uri, "PUT", data, false); + + if (!SkyDriveJsonParser.ContainsError(json, false)) + { + var entryBase = entry as BaseFileEntry; + if (entryBase != null) + entryBase.Name = newName; + return true; + } + + return false; + } + + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry entry, ICloudDirectoryEntry moveTo) + { + if (entry.Name.Equals("/")) + return false; + + var uri = string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var data = string.Format("{{destination: \"{0}\"}}", moveTo.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var json = SkyDriveRequestHelper.PerformRequest(session, uri, "MOVE", data, false); + + if (!SkyDriveJsonParser.ContainsError(json, false)) + { + var parent = entry.Parent as BaseDirectoryEntry; + if (parent != null) + parent.RemoveChildById(entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var moveToBase = moveTo as BaseDirectoryEntry; + if (moveToBase != null) + moveToBase.AddChild(entry as BaseFileEntry); + return true; + } + + return false; + } + + public override bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry entry, ICloudDirectoryEntry copyTo) + { + if (entry.Name.Equals("/")) + return false; + + if (entry is ICloudDirectoryEntry) + { + // skydrive allowes to copy only files so we will recursively create/copy entries + var newEntry = CreateResource(session, entry.Name, copyTo) as ICloudDirectoryEntry; + return newEntry != null && (entry as ICloudDirectoryEntry).Aggregate(true, (current, subEntry) => current && CopyResource(session, subEntry, newEntry)); + } + + var uri = string.Format("{0}/{1}", SkyDriveConstants.BaseAccessUrl, entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var data = string.Format("{{destination: \"{0}\"}}", copyTo.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + var json = SkyDriveRequestHelper.PerformRequest(session, uri, "COPY", data, false); + + if (json != null && !SkyDriveJsonParser.ContainsError(json, false)) + { + var copyToBase = copyTo as BaseDirectoryEntry; + if (copyToBase != null) + copyToBase.AddChild(entry as BaseFileEntry); + return true; + } + + return false; + } + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + if (entry is ICloudDirectoryEntry) + throw new ArgumentException("Download operation can be perform for files only"); + + var uri = string.Format("{0}/{1}/content", SkyDriveConstants.BaseAccessUrl, entry.GetPropertyValue(SkyDriveConstants.InnerIDKey)); + uri = SkyDriveRequestHelper.SignUri(session, uri); + var request = WebRequest.Create(uri); + using (var response = request.GetResponse()) + { + ((BaseFileEntry)entry).Length = response.ContentLength; + return new BaseFileEntryDownloadStream(response.GetResponseStream(), entry); + } + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry entry, long uploadSize) + { + if (entry is ICloudDirectoryEntry) + throw new ArgumentException("Upload operation can be perform for files only"); + + var tempStream = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose); + var uploadStream = new WebRequestStream(tempStream, null, null); + uploadStream.PushPreDisposeOperation(CommitUploadOperation, tempStream, uploadSize, session, entry); + return uploadStream; + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry entry, nTransferDirection direction, Stream notDisposedStream) + { + } + + public override bool SupportsDirectRetrieve + { + get { return true; } + } + + public override void StoreToken(IStorageProviderSession session, Dictionary tokendata, ICloudStorageAccessToken token) + { + if (token is OAuth20Token) + { + tokendata.Add(SkyDriveConstants.SerializedDataKey, (token as OAuth20Token).ToJson()); + } + } + + public override ICloudStorageAccessToken LoadToken(Dictionary tokendata) + { + var type = tokendata[CloudStorage.TokenCredentialType]; + if (type.Equals(typeof (OAuth20Token).ToString())) + { + var json = tokendata[SkyDriveConstants.SerializedDataKey]; + return OAuth20Token.FromJson(json); + } + return null; + } + + private static void CommitUploadOperation(object[] args) + { + var tempStream = (Stream)args[0]; + var contentLength = (long)args[1]; + var session = (IStorageProviderSession)args[2]; + var file = (BaseFileEntry)args[3]; + + var request = (HttpWebRequest)WebRequest.Create(GetSignedUploadUrl(session, file)); + request.Method = "PUT"; + request.ContentLength = contentLength; + request.Timeout = Timeout.Infinite; + + tempStream.Flush(); + tempStream.Seek(0, SeekOrigin.Begin); + + using (var requestSteam = request.GetRequestStream()) + { + tempStream.CopyTo(requestSteam); + } + + tempStream.Close(); + + using (var response = request.GetResponse()) + using (var rs = response.GetResponseStream()) + { + if (rs == null) return; + string json; + using (var streamReader = new StreamReader(rs)) + { + json = streamReader.ReadToEnd(); + } + var id = SkyDriveJsonParser.ParseEntryID(json); + file.Id = id; + file[SkyDriveConstants.InnerIDKey] = id; + file.Modified = DateTime.UtcNow; + + var parent = file.Parent as BaseDirectoryEntry; + if (parent != null) + { + parent.RemoveChildById(file.Name); + parent.AddChild(file); + } + } + + } + + public override string GetResourceUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, string additionalPath) + { + var id = SkyDriveHelpers.GetResourceID(additionalPath); + if (!string.IsNullOrEmpty(id) || additionalPath != null && additionalPath.Equals("/")) + return "/" + id; + if (string.IsNullOrEmpty(additionalPath) && fileSystemEntry != null) + return "/" + (!fileSystemEntry.Id.Equals("/") ? fileSystemEntry.Id : ""); + return base.GetResourceUrl(session, fileSystemEntry, additionalPath); + } + + private static string GetSignedUploadUrl(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + var uri = string.Format("{0}/{1}/files/{2}", + SkyDriveConstants.BaseAccessUrl, + fileSystemEntry.Parent.GetPropertyValue(SkyDriveConstants.InnerIDKey), + fileSystemEntry.Name); + + return SkyDriveRequestHelper.SignUri(session, uri); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderSession.cs new file mode 100644 index 0000000000..14d98aa83b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/Logic/SkyDriveStorageProviderSession.cs @@ -0,0 +1,20 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Logic +{ + internal class SkyDriveStorageProviderSession : IStorageProviderSession + { + public ICloudStorageAccessToken SessionToken { get; set; } + + public IStorageProviderService Service { get; set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; set; } + + public SkyDriveStorageProviderSession(ICloudStorageAccessToken token, IStorageProviderService service, ICloudStorageConfiguration configuration) + { + SessionToken = token; + Service = service; + ServiceConfiguration = configuration; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConfiguration.cs new file mode 100644 index 0000000000..8478017893 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConfiguration.cs @@ -0,0 +1,22 @@ +using System; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive +{ + public class SkyDriveConfiguration : ICloudStorageConfiguration + { + public Uri ServiceLocator + { + get { return new Uri(SkyDriveConstants.BaseAccessUrl); } + } + + public bool TrustUnsecureSSLConnections + { + get { return false; } + } + + public CloudStorageLimits Limits + { + get { return new CloudStorageLimits(100*1024*1024, -1); } + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConstants.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConstants.cs new file mode 100644 index 0000000000..38025706e4 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveConstants.cs @@ -0,0 +1,32 @@ +using System; +using System.Text.RegularExpressions; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive +{ + internal static class SkyDriveConstants + { + //authorization + public const string OAuth20AuthUrl = "https://login.live.com/oauth20_authorize.srf"; + public const string OAuth20TokenUrl = "https://login.live.com/oauth20_token.srf"; + public const string DefaultScopes = "wl.signin wl.skydrive_update wl.offline_access"; + public const string DefaultRedirectUri = "https://login.live.com/oauth20_desktop.srf"; //for desktop and mobile apps only + + //property keys + public const string SerializedDataKey = "serializedData"; + public const string UploadLocationKey = "uploadLocation"; + public const string ParentIDKey = "parentID"; + public const string TimestampKey = "timestamp"; + public const string InnerIDKey = "resourceID"; + + //access paths + public const string BaseAccessUrl = "https://apis.live.net/v5.0"; + public const string RootAccessUrl = BaseAccessUrl + "/me/skydrive"; + public const string FilesAccessUrlFormat = BaseAccessUrl + "/{0}/files"; + + //misc + public static readonly string[] SupportedFileExtensions = new[] { "" }; + public static readonly Regex ResourceIDRegex = new Regex(@"^(file|folder|photo|album)\.[!\.\w]+$", RegexOptions.Compiled | RegexOptions.CultureInvariant); + public static readonly Regex RootIDRegex = new Regex(@"^folder.\w+$"); + + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveHelpers.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveHelpers.cs new file mode 100644 index 0000000000..9fabab078b --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveHelpers.cs @@ -0,0 +1,64 @@ +using System; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive +{ + internal static class SkyDriveHelpers + { + public static bool HasResourceID(string nameOrID) + { + return GetResourceID(nameOrID) != string.Empty; + } + + public static string GetResourceID(string nameOrID) + { + if (string.IsNullOrEmpty(nameOrID)) + return string.Empty; + + var index = nameOrID.LastIndexOf('/'); + if (index != -1 && index != nameOrID.Length) + { + nameOrID = nameOrID.Substring(index + 1); + } + return SkyDriveConstants.ResourceIDRegex.IsMatch(nameOrID) ? nameOrID : string.Empty; + } + + public static bool HasParentID(string nameOrID) + { + return GetParentID(nameOrID) != string.Empty; + } + + public static string GetParentID(string nameOrID) + { + if (string.IsNullOrEmpty(nameOrID)) + return string.Empty; + + var index = nameOrID.LastIndexOf('/'); + if (index != -1 && index != nameOrID.Length) + { + nameOrID = nameOrID.Remove(index); + } + return GetResourceID(nameOrID); + } + + public static bool IsFolderID(string id) + { + return id.StartsWith("folder") || id.StartsWith("album") || id == string.Empty; //empty if root folder with id like "/" + } + + public static void CopyProperties(ICloudFileSystemEntry src, ICloudFileSystemEntry dest) + { + if (!(dest is BaseFileEntry) || !(src is BaseFileEntry)) return; + + var destBase = dest as BaseFileEntry; + var srcBase = src as BaseFileEntry; + destBase.Name = srcBase.Name; + destBase.Id = srcBase.Id; + destBase[SkyDriveConstants.InnerIDKey] = srcBase[SkyDriveConstants.InnerIDKey]; + destBase.Modified = srcBase.Modified; + destBase.Length = srcBase.Length; + destBase[SkyDriveConstants.UploadLocationKey] = srcBase[SkyDriveConstants.UploadLocationKey]; + destBase.ParentID = srcBase.ParentID; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveJsonParser.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveJsonParser.cs new file mode 100644 index 0000000000..f60c605436 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveJsonParser.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.Serialization; +using AppLimit.CloudComputing.SharpBox.Common.Net.Json; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive +{ + [Serializable] + public class SkyDriveParserException : Exception + { + private readonly string _message; + + public override string Message + { + get { return _message; } + } + + public SkyDriveParserException() + : this(string.Empty) + { + } + + public SkyDriveParserException(string message) + { + _message = message; + } + + protected SkyDriveParserException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + internal static class SkyDriveJsonParser + { + public static ICloudFileSystemEntry ParseSingleEntry(IStorageProviderSession session, string json) + { + return ParseSingleEntry(session, json, null); + } + + private static ICloudFileSystemEntry ParseSingleEntry(IStorageProviderSession session, string json, JsonHelper parser) + { + if (json == null) + return null; + + if (parser == null) + parser = CreateParser(json); + + if (ContainsError(json, false, parser)) + return null; + + BaseFileEntry entry; + + var type = parser.GetProperty("type"); + + if (!IsFolderType(type) && !IsFileType(type)) + return null; + + var id = parser.GetProperty("id"); + var name = parser.GetProperty("name"); + var parentID = parser.GetProperty("parent_id"); + var uploadLocation = parser.GetProperty("upload_location"); + var updatedTime = Convert.ToDateTime(parser.GetProperty("updated_time")).ToUniversalTime(); + + if (IsFolderType(type)) + { + var count = parser.GetPropertyInt("count"); + entry = new BaseDirectoryEntry(name, count, updatedTime, session.Service, session) { Id = id }; + } + else + { + var size = Convert.ToInt64(parser.GetProperty("size")); + entry = new BaseFileEntry(name, size, updatedTime, session.Service, session) { Id = id }; + } + entry[SkyDriveConstants.UploadLocationKey] = uploadLocation; + + if (!string.IsNullOrEmpty(parentID)) + { + entry.ParentID = SkyDriveConstants.RootIDRegex.IsMatch(parentID) ? "/" : parentID; + } + else + { + entry.Name = "/"; + entry.Id = "/"; + } + + entry[SkyDriveConstants.InnerIDKey] = id; + entry[SkyDriveConstants.TimestampKey] = DateTime.UtcNow.ToString(CultureInfo.InvariantCulture); + + return entry; + } + + public static string ParseEntryID(string json) + { + var parser = CreateParser(json); + return parser.GetProperty("id"); + } + + public static IEnumerable ParseListOfEntries(IStorageProviderSession session, string json) + { + return ParseListOfEntries(session, json, null); + } + + private static IEnumerable ParseListOfEntries(IStorageProviderSession session, string json, JsonHelper parser) + { + if (json == null) + return null; + + if (parser == null) + parser = CreateParser(json); + + if (ContainsError(json, false, parser)) + return null; + + return parser.GetListProperty("data").Select(jsonEntry => ParseSingleEntry(session, jsonEntry)).Where(entry => entry != null); + } + + public static bool ContainsError(string json, bool throwIfError) + { + return ContainsError(json, throwIfError, null); + } + + private static bool ContainsError(string json, bool throwIfError, JsonHelper parser) + { + if (string.IsNullOrEmpty(json)) + return false; + + if (parser == null) + parser = CreateParser(json); + + var error = parser.GetProperty("error"); + + if (!string.IsNullOrEmpty(error)) + { + if (throwIfError) + throw new SkyDriveParserException( + string.Format("The returned JSON message is describing the error. The message contained the following: {0}", error)); + + return true; + } + + return false; + } + + private static JsonHelper CreateParser(string json) + { + var parser = new JsonHelper(); + if (!parser.ParseJsonMessage(json)) + throw new SkyDriveParserException("Can not parse this JSON message"); + return parser; + } + + private static bool IsFolderType(string type) + { + return type.Equals("folder") || type.Equals("album"); + } + + private static bool IsFileType(string type) + { + return type.Equals("file") || type.Equals("photo"); + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveRequestHelper.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveRequestHelper.cs new file mode 100644 index 0000000000..d259280f3c --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/SkyDrive/SkyDriveRequestHelper.cs @@ -0,0 +1,165 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Authorization; +using AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive.Logic; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.SkyDrive +{ + internal static class SkyDriveRequestHelper + { + public static string SignUri(IStorageProviderSession session, string uri) + { + var token = GetValidToken(session); + var signedUri = string.Format("{0}?access_token={1}", uri, token.AccessToken); + return signedUri; + } + + private static OAuth20Token GetValidToken(IStorageProviderSession session) + { + var token = session.SessionToken as OAuth20Token; + if (token == null) throw new ArgumentException("Can not retrieve valid oAuth 2.0 token from given session", "session"); + if (token.IsExpired) + { + token = (OAuth20Token)SkyDriveAuthorizationHelper.RefreshToken(token); + var sdSession = session as SkyDriveStorageProviderSession; + if (sdSession != null) + { + sdSession.SessionToken = token; + } + } + return token; + } + + public static string PerformRequest(IStorageProviderSession session, string uri) + { + return PerformRequest(session, uri, true); + } + + public static string PerformRequest(IStorageProviderSession session, string uri, bool signUri) + { + return PerformRequest(session, uri, "GET", signUri); + } + + public static string PerformRequest(IStorageProviderSession session, string uri, string method, bool signUri) + { + return PerformRequest(session, uri, method, null, signUri); + } + + public static string PerformRequest(IStorageProviderSession session, string uri, string method, string data, bool signUri) + { + return PerformRequest(session, uri, method, data, signUri, 2); + } + + public static string PerformRequest(IStorageProviderSession session, string uri, string method, string data, bool signUri, int countAttempts) + { + if (string.IsNullOrEmpty(method)) + method = "GET"; + + if (!string.IsNullOrEmpty(data) && method == "GET") + return null; + + if (signUri) + uri = SignUri(session, uri); + + + var attemptsToComplete = countAttempts; + while (attemptsToComplete > 0) + { + var request = WebRequest.Create(uri); + request.Method = method; + request.Timeout = 5000; + + if (!signUri) + request.Headers.Add("Authorization", "Bearer " + GetValidToken(session).AccessToken); + + if (!string.IsNullOrEmpty(data)) + { + var bytes = Encoding.UTF8.GetBytes(data); + request.ContentType = "application/json"; + request.ContentLength = bytes.Length; + using (var rs = request.GetRequestStream()) + { + rs.Write(bytes, 0, bytes.Length); + } + } + + try + { + using (var response = request.GetResponse()) + using (var rs = response.GetResponseStream()) + { + if (rs != null) + { + using (var streamReader = new StreamReader(rs)) + { + return streamReader.ReadToEnd(); + } + } + } + return null; + } + catch (WebException exception) + { + attemptsToComplete--; + + if (exception.Response != null && ((HttpWebResponse)exception.Response).StatusCode == HttpStatusCode.NotFound) + return null; + } + } + return null; + } + + public static string PerformRequest(string uri, string contentType, string method, string queryString, int countAttempts) + { + if (string.IsNullOrEmpty(uri)) + throw new ArgumentException("Uri can't be empty string.", "uri"); + + if (string.IsNullOrEmpty(method)) + method = "GET"; + + byte[] bytes = null; + if (!string.IsNullOrEmpty(queryString)) + bytes = Encoding.UTF8.GetBytes(queryString); + + var attemptsToTry = countAttempts; + while (attemptsToTry > 0) + { + var request = WebRequest.Create(uri); + request.Method = method; + request.Timeout = 5000; + if (request.Method != "GET" && !string.IsNullOrEmpty(contentType) && bytes != null) + { + request.ContentType = contentType; + request.ContentLength = bytes.Length; + using (var stream = request.GetRequestStream()) + { + stream.Write(bytes, 0, bytes.Length); + } + } + try + { + using (var response = request.GetResponse()) + using (var stream = response.GetResponseStream()) + { + if (stream != null) + using (var streamReader = new StreamReader(stream)) + { + return streamReader.ReadToEnd(); + } + return null; + } + } + catch (WebException) + { + attemptsToTry--; + request.Abort(); + } + } + return null; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavRequestParser.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavRequestParser.cs new file mode 100644 index 0000000000..acaf1d717d --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavRequestParser.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Web; +using System.Xml.Linq; +using AppLimit.CloudComputing.SharpBox.Common.Extensions; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Common.Net; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic +{ + internal delegate string NameBaseFilterCallback(string targetUrl, IStorageProviderService service, IStorageProviderSession session, string nameBase); + + internal class WebDavRequestResult + { + public BaseFileEntry Self { get; set; } + public List Childs { get; set; } + + public WebDavRequestResult() + { + Childs = new List(); + } + } + + internal class WebDavRequestParser + { + private const string DavNamespace = "DAV:"; + private const string HttpOk = "HTTP/1.1 200 OK"; + + public static WebDavRequestResult CreateObjectsFromNetworkStream(Stream data, string targetUrl, IStorageProviderService service, IStorageProviderSession session, NameBaseFilterCallback callback) + { + var config = session.ServiceConfiguration as WebDavConfiguration; + var results = new WebDavRequestResult(); + + var queryLessUri = HttpUtilityEx.GetPathAndQueryLessUri(config.ServiceLocator).ToString().TrimEnd('/'); + var decodedTargetUrl = HttpUtility.UrlDecode(targetUrl); + string s; + using (var streamReader = new StreamReader(data)) + { + s = streamReader.ReadToEnd(); + } + //todo: + var xDoc = XDocument.Load(new StringReader(s.Replace("d:d:", "d:"))); + var responses = xDoc.Descendants(XName.Get("response", DavNamespace)); + + foreach (var response in responses) + { + var isHidden = false; + var isDirectory = false; + var lastModified = DateTime.Now; + long contentLength = 0; + + var href = response.Element(XName.Get("href", DavNamespace)).ValueOrEmpty(); + var propstats = response.Descendants(XName.Get("propstat", DavNamespace)); + foreach (var propstat in propstats) + { + var prop = propstat.Element(XName.Get("prop", DavNamespace)); + var status = propstat.Element(XName.Get("status", DavNamespace)).ValueOrEmpty(); + + if (!status.Equals(HttpOk) || prop == null) continue; + + var strLastModified = prop.Element(XName.Get("getlastmodified", DavNamespace)).ValueOrEmpty(); + var strContentLength = prop.Element(XName.Get("getcontentlength", DavNamespace)).ValueOrEmpty(); + var resourceType = prop.Element(XName.Get("resourcetype", DavNamespace)); + var strIsHidden = prop.Element(XName.Get("ishidden", DavNamespace)).ValueOrEmpty(); + + if (!string.IsNullOrEmpty(strIsHidden)) + { + int code; + if (!int.TryParse(strIsHidden, out code)) + code = 0; + isHidden = Convert.ToBoolean(code); + } + if (resourceType != null && resourceType.Element(XName.Get("collection", DavNamespace)) != null) + isDirectory = true; + if (!string.IsNullOrEmpty(strContentLength)) + contentLength = Convert.ToInt64(strContentLength); + if (!string.IsNullOrEmpty(strLastModified) && DateTime.TryParse(strLastModified, out lastModified)) + { + lastModified = lastModified.ToUniversalTime(); + } + } + + //entry not to be encluded + if (isHidden) continue; + + var nameBase = href; + + if (callback != null) + nameBase = callback(targetUrl, service, session, nameBase); + + string nameBaseForSelfCheck; + + if (nameBase.StartsWith(config.ServiceLocator.ToString())) + { + nameBaseForSelfCheck = HttpUtility.UrlDecode(nameBase); + nameBase = nameBase.Remove(0, config.ServiceLocator.ToString().Length); + } + else + { + nameBaseForSelfCheck = queryLessUri + HttpUtilityEx.PathDecodeUTF8(nameBase); + } + + nameBase = nameBase.TrimEnd('/'); + nameBaseForSelfCheck = nameBaseForSelfCheck.TrimEnd('/'); + if (targetUrl.EndsWith("/")) + nameBaseForSelfCheck += "/"; + + var isSelf = nameBaseForSelfCheck.Equals(decodedTargetUrl); + + var ph = new PathHelper(nameBase); + var resourceName = HttpUtility.UrlDecode(ph.GetFileName()); + + var entry = !isDirectory + ? new BaseFileEntry(resourceName, contentLength, lastModified, service, session) + : new BaseDirectoryEntry(resourceName, contentLength, lastModified, service, session); + + if (isSelf) + { + results.Self = entry; + } + else + { + results.Childs.Add(entry); + } + } + + return results; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderService.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderService.cs new file mode 100644 index 0000000000..efa36ce00a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderService.cs @@ -0,0 +1,562 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text.RegularExpressions; +using AppLimit.CloudComputing.SharpBox.Common.IO; +using AppLimit.CloudComputing.SharpBox.Common.Net; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web; +using AppLimit.CloudComputing.SharpBox.Common.Net.Web.Dav; +using AppLimit.CloudComputing.SharpBox.Exceptions; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; +using AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic +{ + internal class WebDavStorageProviderService : GenericStorageProviderService + { + #region IStorageProviderService Members + + /// + /// Verifies if the given credentials are valid webdav credentials + /// + /// + /// + public override bool VerifyAccessTokenType(ICloudStorageAccessToken token) + { + return (token is ICredentials); + } + + /// + /// This method generates a session to a webdav share via username and password + /// + /// + /// + /// + public override IStorageProviderSession CreateSession(ICloudStorageAccessToken token, ICloudStorageConfiguration configuration) + { + // cast the creds to the right type + var config = configuration as WebDavConfiguration; + + // build service + var svc = new DavService(); + + // check if url available + int status; + WebException e; + svc.PerformSimpleWebCall(config.ServiceLocator.ToString(), WebRequestMethodsEx.WebDAV.Options, (token as ICredentials).GetCredential(null, null), null, out status, out e); + if (status == (int)HttpStatusCode.Unauthorized) + throw new UnauthorizedAccessException(); + if (HttpUtilityEx.IsSuccessCode(status)) + return new WebDavStorageProviderSession(token, config, this); + return null; + } + + /// + /// This method request information about a resource + /// + /// + /// + /// + /// + public override ICloudFileSystemEntry RequestResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + // build url + var uriString = GetResourceUrl(session, parent, null); + uriString = PathHelper.Combine(uriString, name); + + // get the data + List childs; + var requestResource = RequestResourceFromWebDavShare(session, uriString, out childs); + + // check errors + if (requestResource == null) + return null; + + // rename the root + if (name.Equals("/")) + requestResource.Name = "/"; + + // init parent child relation + if (parent != null) + { + var parentDir = parent as BaseDirectoryEntry; + parentDir.AddChild(requestResource); + } + + // check if we have to add childs + if (!(requestResource is BaseDirectoryEntry)) + return requestResource; + + var requestedDir = requestResource as BaseDirectoryEntry; + + // add the childs + foreach (var child in childs) + { + requestedDir.AddChild(child); + } + + // go ahead + return requestResource; + } + + public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource) + { + // nothing to do for files + if (!(resource is ICloudDirectoryEntry)) + return; + + // build url + var uriString = GetResourceUrl(session, resource, null); + + // get the data + List childs; + RequestResourceFromWebDavShare(session, uriString, out childs); + + // set the new childs collection + var dirEntry = resource as BaseDirectoryEntry; + dirEntry.ClearChilds(); + + // add the new childs + if (childs != null) + dirEntry.AddChilds(childs); + } + + + /// + /// + /// + /// + /// + /// + /// + public override ICloudFileSystemEntry CreateResource(IStorageProviderSession session, string name, ICloudDirectoryEntry parent) + { + // get the credentials + var creds = session.SessionToken as ICredentials; + + // build url + var uriString = GetResourceUrl(session, parent, null); + uriString = PathHelper.Combine(uriString, name); + + var uri = new Uri(uriString); + + // build the DavService + var svc = new DavService(); + + // create the webrequest + int errorCode; + WebException e; + svc.PerformSimpleWebCall(uri.ToString(), WebRequestMethodsEx.Http.MkCol, creds.GetCredential(null, null), null, out errorCode, out e); + if (errorCode != (int)HttpStatusCode.Created) + return null; + + var newDir = new BaseDirectoryEntry(name, 0, DateTime.Now, this, session); + + // init parent child relation + if (parent != null) + { + var parentDir = parent as BaseDirectoryEntry; + parentDir.AddChild(newDir); + } + + return newDir; + } + + /// + /// This method removes a specific resource from a webdav share + /// + /// + /// + public override bool DeleteResource(IStorageProviderSession session, ICloudFileSystemEntry entry) + { + // get the credentials + var creds = session.SessionToken as ICredentials; + + // build url + var uriString = GetResourceUrl(session, entry, null); + var uri = new Uri(uriString); + + // create the service + var svc = new DavService(); + + // create the webrequest + int errorCode; + WebException e; + svc.PerformSimpleWebCall(uri.ToString(), WebRequestMethodsEx.WebDAV.Delete, creds.GetCredential(null, null), null, out errorCode, out e); + if (!HttpUtilityEx.IsSuccessCode(errorCode)) + return false; + + // remove from parent + var parentDir = entry.Parent as BaseDirectoryEntry; + if (parentDir != null) + { + parentDir.RemoveChildById(entry.Id); + } + + return true; + + } + + /// + /// This method moves a resource from one webdav location to an other + /// + /// + /// + /// + /// + public override bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + // build the targte url + var uriStringTarget = GetResourceUrl(session, newParent, null); + uriStringTarget = PathHelper.Combine(uriStringTarget, fsentry.Name); + + if (!MoveResource(session, fsentry, uriStringTarget)) + return false; + + // readjust parent + var oldParent = fsentry.Parent as BaseDirectoryEntry; + if (oldParent != null) + { + oldParent.RemoveChild(fsentry as BaseFileEntry); + } + + var newParentObject = newParent as BaseDirectoryEntry; + if (newParentObject != null) + { + newParentObject.AddChild(fsentry as BaseFileEntry); + } + + return true; + } + + public override bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, ICloudDirectoryEntry newParent) + { + // build the targte url + var uriStringTarget = GetResourceUrl(session, newParent, null); + uriStringTarget = PathHelper.Combine(uriStringTarget, fsentry.Name); + + if (!CopyResource(session, fsentry, uriStringTarget)) + return false; + + var newParentObject = newParent as BaseDirectoryEntry; + if (newParentObject != null) + { + newParentObject.AddChild(fsentry as BaseFileEntry); + } + + return true; + } + + /// + /// Renames a webdave file or folder + /// + /// + /// + /// + /// + public override bool RenameResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newName) + { + // build the targte url + var uriStringTarget = GetResourceUrl(session, fsentry.Parent, null); + uriStringTarget = PathHelper.Combine(uriStringTarget, newName); + + if (MoveResource(session, fsentry, uriStringTarget)) + { + // rename the fsentry + var fentry = fsentry as BaseFileEntry; + fentry.Name = newName; + + // go ahead + return true; + } + + // go ahead + return false; + } + + #endregion + + public override Stream CreateDownloadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry) + { + // build the url + var url = GetResourceUrl(session, fileSystemEntry, null); + + // get the session creds + var creds = session.SessionToken as ICredentials; + + // Build the service + var svc = new DavService(); + + // create the response + var response = CreateDownloadResponse(url, creds.GetCredential(null, null)); + + // get the data + var orgStream = svc.GetResponseStream(response); + + var dStream = new BaseFileEntryDownloadStream(orgStream, fileSystemEntry); + + // put the disposable on the stack + dStream._DisposableObjects.Push(response); + + // go ahead + return dStream; + } + + private WebResponse CreateDownloadResponse(string url, ICredentials creds) + { + // Build the service + var svc = new DavService(); + + // create the webrequest + var request = svc.CreateWebRequest(url, WebRequestMethodsEx.Http.Get, creds, false, null); + + try + { + // create the response + var response = svc.GetWebResponse(request); + return response; + } + catch (WebException e) + { + if (e.Response is HttpWebResponse) + { + var code = (e.Response as HttpWebResponse).StatusCode; + if (code == HttpStatusCode.Moved) + { + // get the new uri + var newUri = e.Response.Headers["Location"]; + + // redo it + return CreateDownloadResponse(newUri, creds); + } + + NetworkCredential networkCredential; + if (code == HttpStatusCode.Unauthorized && (networkCredential = creds as NetworkCredential) != null) + { + var search = new Regex(@"^\w+", RegexOptions.Singleline | RegexOptions.IgnoreCase); + // get authentication method + var authMethod = search.Match(e.Response.Headers["WWW-Authenticate"]).Value; + var newCredentials = new CredentialCache { { new Uri((new Uri(url)).GetLeftPart(UriPartial.Authority)), authMethod, networkCredential } }; + + // redo it + return CreateDownloadResponse(url, newCredentials); + } + } + + throw; + } + } + + public override Stream CreateUploadStream(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, long uploadSize) + { + // build the url + var url = GetResourceUrl(session, fileSystemEntry, null); + + // get the session creds + var creds = session.SessionToken as ICredentials; + + // Build the service + var svc = new DavService(); + + // get the service config + var conf = (WebDavConfiguration)session.ServiceConfiguration; + + // build the webrequest + var networkRequest = svc.CreateWebRequestPUT(url, creds.GetCredential(null, null), conf.UploadDataStreambuffered); + + // get the request stream + var requestStream = svc.GetRequestStream(networkRequest, uploadSize); + + // add disposal opp + requestStream.PushPostDisposeOperation(CommitUploadStream, svc, networkRequest, fileSystemEntry, requestStream); + + // go ahead + return requestStream; + } + + public override bool SupportsDirectRetrieve + { + get { return false; } + } + + public void CommitUploadStream(params object[] arg) + { + // convert the args + var svc = arg[0] as DavService; + var uploadRequest = arg[1] as HttpWebRequest; + var fileSystemEntry = arg[2] as BaseFileEntry; + + var requestStream = arg[3] as WebRequestStream; + + // check if all data was written into stream + if (requestStream.WrittenBytes != uploadRequest.ContentLength) + // nothing todo request was aborted + return; + + // perform the request + int code; + WebException e; + svc.PerformWebRequest(uploadRequest, null, out code, out e); + + // check the ret value + if (!HttpUtilityEx.IsSuccessCode(code)) + SharpBoxException.ThrowSharpBoxExceptionBasedOnHttpErrorCode(uploadRequest, (HttpStatusCode)code, e); + + // adjust the lengt + fileSystemEntry.Length = uploadRequest.ContentLength; + } + + public override void CommitStreamOperation(IStorageProviderSession session, ICloudFileSystemEntry fileSystemEntry, nTransferDirection direction, Stream notDisposedStream) + { + } + + #region Helper + + private static bool MoveResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newTargetUrl) + { + var config = session.ServiceConfiguration as WebDavConfiguration; + var creds = session.SessionToken as ICredentials; + + var uriString = PathHelper.Combine(config.ServiceLocator.ToString(), GenericHelper.GetResourcePath(fsentry)); + + var uri = new Uri(uriString); + var uriTarget = new Uri(newTargetUrl); + + var errorCode = new DavService().PerformMoveWebRequest(uri.ToString(), uriTarget.ToString(), creds.GetCredential(null, null)); + + return errorCode == HttpStatusCode.Created || errorCode == HttpStatusCode.NoContent; + } + + private bool CopyResource(IStorageProviderSession session, ICloudFileSystemEntry fsentry, string newTargetUrl) + { + var config = session.ServiceConfiguration as WebDavConfiguration; + var creds = session.SessionToken as ICredentials; + + var uriString = PathHelper.Combine(config.ServiceLocator.ToString(), GenericHelper.GetResourcePath(fsentry)); + + var uri = new Uri(uriString); + var uriTarget = new Uri(newTargetUrl); + + var errorCode = new DavService().PerformCopyWebRequest(uri.ToString(), uriTarget.ToString(), creds.GetCredential(null, null)); + + return errorCode == HttpStatusCode.Created || errorCode == HttpStatusCode.NoContent + || errorCode == HttpStatusCode.Accepted && uriString.StartsWith(WebDavConfiguration.YaUrl); + } + + private BaseFileEntry RequestResourceFromWebDavShare(IStorageProviderSession session, string resourceUrl, out List childs) + { + // get the credebtials + var creds = session.SessionToken as ICredentials; + return RequestResourceFromWebDavShare(session, creds.GetCredential(null, null), resourceUrl, out childs); + } + + private BaseFileEntry RequestResourceFromWebDavShare(IStorageProviderSession session, ICredentials creds, string resourceUrl, out List childs) + { + // build the dav service + var svc = new DavService(); + + try + { + // create the web request + var request = svc.CreateWebRequestPROPFIND(resourceUrl, creds); + + // the result + WebDavRequestResult requestResult; + + // get the response + using (var response = svc.GetWebResponse(request) as HttpWebResponse) + { + if (response.StatusCode == HttpStatusCode.Moved) + { + // get the new uri + var newUri = response.Headers["Location"]; + (session.ServiceConfiguration as WebDavConfiguration).ServiceLocator = new Uri(newUri); + + // close the response + response.Close(); + + // redo it + return RequestResourceFromWebDavShare(session, creds, newUri, out childs); + } + + // get the response stream + using (var data = svc.GetResponseStream(response)) + { + if (data == null) + { + childs = null; + return null; + } + + // build the file entries + requestResult = WebDavRequestParser.CreateObjectsFromNetworkStream(data, resourceUrl, this, session, WebDavNameBaseFilterCallback); + + // close the stream + data.Close(); + } + + // close the response + response.Close(); + } + + // get the request fileentry and fill the childs + if (requestResult.Self == null) + { + childs = null; + return null; + } + + // set the childs + childs = requestResult.Childs; + + // go ahead + return requestResult.Self; + } + catch (WebException e) + { + if (e.Response is HttpWebResponse) + { + var code = (e.Response as HttpWebResponse).StatusCode; + if (code == HttpStatusCode.Moved) + { + // get the new uri + var newUri = e.Response.Headers["Location"]; + (session.ServiceConfiguration as WebDavConfiguration).ServiceLocator = new Uri(newUri); + + // redo it + return RequestResourceFromWebDavShare(session, creds, newUri, out childs); + } + + NetworkCredential networkCredential; + if (code == HttpStatusCode.Unauthorized && (networkCredential = creds as NetworkCredential) != null) + { + var search = new Regex(@"^\w+", RegexOptions.Singleline | RegexOptions.IgnoreCase); + // get authentication method + var authMethod = search.Match(e.Response.Headers["WWW-Authenticate"]).Value; + var newCredentials = new CredentialCache { { new Uri((new Uri(resourceUrl)).GetLeftPart(UriPartial.Authority)), authMethod, networkCredential } }; + + // redo it + return RequestResourceFromWebDavShare(session, newCredentials, resourceUrl, out childs); + } + } + + childs = null; + return null; + } + } + + private string WebDavNameBaseFilterCallback(string targetUrl, IStorageProviderService service, IStorageProviderSession session, string NameBase) + { + // call our virtual method + return OnNameBase(targetUrl, service, session, NameBase); + } + + protected virtual string OnNameBase(string targetUrl, IStorageProviderService service, IStorageProviderSession session, string nameBase) + { + return nameBase; + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderSession.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderSession.cs new file mode 100644 index 0000000000..920e9cdb72 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/Logic/WebDavStorageProviderSession.cs @@ -0,0 +1,24 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic +{ + internal class WebDavStorageProviderSession : IStorageProviderSession + { + public WebDavStorageProviderSession(ICloudStorageAccessToken token, WebDavConfiguration config, IStorageProviderService service) + { + SessionToken = token; + ServiceConfiguration = config; + Service = service; + } + + #region IStorageProviderSession Members + + public ICloudStorageAccessToken SessionToken { get; private set; } + + public IStorageProviderService Service { get; private set; } + + public ICloudStorageConfiguration ServiceConfiguration { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavConfiguration.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavConfiguration.cs new file mode 100644 index 0000000000..00b602dd4a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavConfiguration.cs @@ -0,0 +1,180 @@ +using System; +using System.Net; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav +{ + /// + /// This class implements all BoxNet specific configurations + /// + public class WebDavConfiguration : ICloudStorageConfiguration + { + private bool _trustUnsecureSslConnections = true; + + /// + /// The url of webserver which has to be used for access to a specific + /// webdav share. + /// + private Uri WebServer { get; set; } + + /// + /// ctor of the Box.Net configuration + /// + public WebDavConfiguration(Uri uriWebDavServer) + { + WebServer = uriWebDavServer; + UploadDataStreambuffered = false; + } + + /// + /// Specifies if we allow not secure ssl connections + /// + public bool TrustUnsecureSSLConnections + { + get { return _trustUnsecureSslConnections; } + set { _trustUnsecureSslConnections = value; } + } + + /// + /// Specifies if the webdavclient should upload the data + /// stream buffered. Detailed is fales to reduce the + /// memory foodprint! + /// + public bool UploadDataStreambuffered { get; set; } + + /// + /// This method returns a standard configuration for 1and1 + /// + /// + public static WebDavConfiguration Get1and1Configuration() + { + // set the right url + var config = new WebDavConfiguration(new Uri("https://sd2dav.1und1.de")) + { + Limits = new CloudStorageLimits + { + MaxDownloadFileSize = 500*1024*1024, + MaxUploadFileSize = 500*1024*1024 + }, + + // 1and1 does not support a valid ssl + TrustUnsecureSSLConnections = true, + }; + + // go ahead + return config; + } + + /// + /// This method returns a standard cofiguration for StoreGate + /// + /// + /// + public static WebDavConfiguration GetStoreGateConfiguration(NetworkCredential credentials) + { + // set the right url + var config = new WebDavConfiguration(new Uri("https://webdav1.storegate.com/" + credentials.UserName + "/home/" + credentials.UserName)) + { + Limits = new CloudStorageLimits + { + MaxDownloadFileSize = -1, + MaxUploadFileSize = -1 + }, + // box.net does not support a valid ssl + TrustUnsecureSSLConnections = false + }; + + // go ahead + return config; + } + + /// + /// This method returns a standard cofiguration for CloudMe + /// + /// + /// + public static WebDavConfiguration GetCloudMeConfiguration(NetworkCredential credentials) + { + // set the right url + var config = new WebDavConfiguration(new Uri("http://webdav.cloudme.com/" + credentials.UserName + "/xios")) + { + Limits = new CloudStorageLimits + { + MaxDownloadFileSize = -1, + MaxUploadFileSize = -1 + }, + + // box.net does not support a valid ssl + TrustUnsecureSSLConnections = false, + + // set streambuffered transfer + UploadDataStreambuffered = true + }; + + // go ahead + return config; + } + + /// + /// This method returns a standard configuration for Strato HiDrive + /// + /// + public static WebDavConfiguration GetHiDriveConfiguration() + { + // set the right url + var config = new WebDavConfiguration(new Uri("https://webdav.hidrive.strato.com")) + { + Limits = new CloudStorageLimits + { + MaxDownloadFileSize = -1, + MaxUploadFileSize = -1 + }, + + // box.net does not support a valid ssl + TrustUnsecureSSLConnections = false + }; + + // go ahead + return config; + } + + public const string YaUrl = "https://webdav.yandex.ru"; + public static WebDavConfiguration GetYandexConfiguration() + { + var config = new WebDavConfiguration(new Uri(YaUrl)) + { + TrustUnsecureSSLConnections = false + }; + return config; + } + + #region ICloudStorageConfiguration Members + + private CloudStorageLimits _limits = new CloudStorageLimits + { + MaxDownloadFileSize = -1, + MaxUploadFileSize = -1 + }; + + /// + /// Sets or gets the limits of a webdav configuration + /// + public CloudStorageLimits Limits + { + get { return _limits; } + + set { _limits = value; } + } + + /// + /// Gets the webdav service url + /// + public Uri ServiceLocator + { + get { return WebServer; } + + set { WebServer = value; } + } + + #endregion + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavStorageProvider.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavStorageProvider.cs new file mode 100644 index 0000000000..85ee50999a --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/StorageProvider/WebDav/WebDavStorageProvider.cs @@ -0,0 +1,18 @@ +using AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav.Logic; +using AppLimit.CloudComputing.SharpBox.StorageProvider.API; + +namespace AppLimit.CloudComputing.SharpBox.StorageProvider.WebDav +{ + internal class WebDavStorageProvider : GenericStorageProvider + { + public WebDavStorageProvider() + : base(new CachedServiceWrapper(new WebDavStorageProviderService())) + { + } + + public WebDavStorageProvider(IStorageProviderService svc) + : base(new CachedServiceWrapper(svc)) + { + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiff.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiff.cs new file mode 100644 index 0000000000..cc476e1abf --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiff.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.SyncFramework +{ + /// + /// This class generates the differences between two folders, one on the local + /// filesystem and one in the cloud + /// + internal class DirectoryDiff + { + private readonly DirectoryInfo _localPath; + private readonly ICloudDirectoryEntry _remotePath; + + /// + /// ctor for DirectoryDiff + /// + /// path of the local directory + /// path of the remote directory + public DirectoryDiff(DirectoryInfo localPath, ICloudDirectoryEntry remotePath) + { + _localPath = localPath; + _remotePath = remotePath; + } + + /// + /// compares a local and a remote directory. The result will be a list of differences! + /// + /// check also sub directories + /// + public List Compare(bool bRecursive) + { + // 1. create a recursive local file list + var localFiles = CreateLocalFileList(_localPath, bRecursive); + + // 2. create a recursive remote file list + var remoteFiles = CreateRemoteFileList(_remotePath, bRecursive); + + // 3. create the result list + var result = new List(); + + // 4. performe a sorted list comparation + var i = 0; + var j = 0; + var m = Math.Max(localFiles.Keys.Count, remoteFiles.Keys.Count); + + while (i < m) + { + string left = null; + string right = null; + + if (i < localFiles.Keys.Count) + left = localFiles.Keys.ElementAt(i); + + if (j < remoteFiles.Keys.Count) + right = remoteFiles.Keys.ElementAt(j); + + var ritem = new DirectoryDiffResultItem(); + + if (right == null) + { + // right list is at end, all left items are missing + ritem.localItem = localFiles.Values.ElementAt(i); + ritem.remoteItem = null; + ritem.compareResult = ComparisonResult.MissingInRemoteFolder; + + // increase local + i++; + } + else if (left == null) + { + // left list is at end, all rightitems are missing + ritem.localItem = null; + ritem.remoteItem = remoteFiles.Values.ElementAt(j); + ritem.compareResult = ComparisonResult.MissingInLocalFolder; + + // increase remote + j++; + } + else + { + // compare both elements + var iRet = left.CompareTo(right); + + if (iRet == 0) + { + // are the same elements + ritem.localItem = localFiles.Values.ElementAt(i); + ritem.remoteItem = remoteFiles.Values.ElementAt(j); + + // compare the size + + // set the result + ritem.compareResult = ComparisonResult.Identical; + + // increase both + i++; + j++; + } + else if (iRet < 0) + { + // local missing in remote + ritem.localItem = localFiles.Values.ElementAt(i); + ritem.compareResult = ComparisonResult.MissingInRemoteFolder; + + // increase in local + i++; + } + else + { + // remote missing in local + ritem.remoteItem = remoteFiles.Values.ElementAt(j); + ritem.compareResult = ComparisonResult.MissingInLocalFolder; + + // increase in remote + j++; + } + } + + result.Add(ritem); + } + + return result; + } + + private static SortedDictionary CreateRemoteFileList(ICloudDirectoryEntry start, bool bRescusive) + { + // result + var result = new SortedDictionary(); + + // directoryStack + var directoryStack = new Stack(); + + // add the start directory to the stack + directoryStack.Push(start); + + // do enumeration until stack is empty + while (directoryStack.Count > 0) + { + var current = directoryStack.Pop(); + + foreach (var fsinfo in current) + { + if (fsinfo is ICloudDirectoryEntry) + { + // check if recursion allowed + if (bRescusive == false) + continue; + + // push the directory to stack + directoryStack.Push(fsinfo as ICloudDirectoryEntry); + } + + // build the path + var path = CloudStorage.GetFullCloudPath(fsinfo, Path.DirectorySeparatorChar); + var startpath = CloudStorage.GetFullCloudPath(start, Path.DirectorySeparatorChar); + path = path.Remove(0, startpath.Length); + + // add the entry to our output list + result.Add(path, fsinfo); + } + } + + return result; + } + + private static SortedDictionary CreateLocalFileList(DirectoryInfo start, bool bRescusive) + { + // result + var result = new SortedDictionary(); + + // directoryStack + var directoryStack = new Stack(); + + // add the start directory to the stack + directoryStack.Push(start); + + // do enumeration until stack is empty + while (directoryStack.Count > 0) + { + var current = directoryStack.Pop(); + + foreach (var fsinfo in current.GetFileSystemInfos()) + { + if ((fsinfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + { + // check if recursion allowed + if (bRescusive == false) + continue; + + // push the directory to stack + directoryStack.Push(fsinfo as DirectoryInfo); + } + + // build path + var path = fsinfo.FullName; + path = path.Remove(0, start.FullName.Length); + + // add the entry to our output list + result.Add(path, fsinfo); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiffResultItem.cs b/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiffResultItem.cs new file mode 100644 index 0000000000..b8566b75d7 --- /dev/null +++ b/thirdparty/AppLimit.CloudComputing.SharpBox/SyncFramework/DirectoryDiffResultItem.cs @@ -0,0 +1,40 @@ +using System.IO; + +namespace AppLimit.CloudComputing.SharpBox.SyncFramework +{ + /// + /// Describes the comparison results between scanned files and directories. + /// + internal enum ComparisonResult + { + /// + /// The two files are identical. That means, they have the same size. There + /// is nothing such as a CRC check. + /// + Identical = 0, + + /// + /// The file is present in the local folder but is missing in the remote one. + /// This is also raised for missing folders. + /// + MissingInLocalFolder, + + /// + /// The file is present in the local folder but is missing in the remote one. + /// This is also raised for missing folders. + /// + MissingInRemoteFolder, + + /// + /// The two files have different sizes. + /// + SizeDifferent + } + + internal class DirectoryDiffResultItem + { + public FileSystemInfo localItem; + public ICloudFileSystemEntry remoteItem; + public ComparisonResult compareResult; + } +} \ No newline at end of file From 212fb746c9f7514d7227d94b5bbd43be25553596 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Mon, 16 Mar 2020 11:25:39 +0300 Subject: [PATCH 14/30] Files: thirdparty fix --- .../Core/CustomEndpointDataSource.cs | 12 +- common/ASC.Api.Core/Routing/FormatRoute.cs | 2 + .../Server/Controllers/FilesController.cs | 2 +- .../Server/Core/Dao/TeamlabDao/DaoFactory.cs | 1 + .../Thirdparty/ProviderDao/ProviderFileDao.cs | 1 + .../ProviderDao/ProviderFolderDao.cs | 1 + .../Thirdparty/ProviderDao/ProviderTagDao.cs | 136 ++++++++++++++++++ 7 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs diff --git a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs index b76efe7538..f78a31458e 100644 --- a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs +++ b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs @@ -1,5 +1,8 @@ using System.Collections.Generic; using System.Linq; + +using ASC.Web.Api.Routing; + using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Patterns; @@ -16,7 +19,14 @@ namespace ASC.Api.Core.Core { Source = source; var endpoints = Source.Endpoints.Cast(); - Endpoints = endpoints.Select(r => new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}"), r.Order, r.Metadata, r.DisplayName)).ToList(); + Endpoints = endpoints + .Where(r => + { + var attr = r.Metadata.OfType().FirstOrDefault(); + return attr == null || !attr.DisableFormat; + }) + .Select(r => new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}"), r.Order, r.Metadata, r.DisplayName)) + .ToList(); } public override IChangeToken GetChangeToken() diff --git a/common/ASC.Api.Core/Routing/FormatRoute.cs b/common/ASC.Api.Core/Routing/FormatRoute.cs index 6cbd21c717..c10998e402 100644 --- a/common/ASC.Api.Core/Routing/FormatRoute.cs +++ b/common/ASC.Api.Core/Routing/FormatRoute.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net.Http; + using Microsoft.AspNetCore.Mvc.Routing; namespace ASC.Web.Api.Routing @@ -7,6 +8,7 @@ namespace ASC.Web.Api.Routing public abstract class CustomHttpMethodAttribute : HttpMethodAttribute { public bool Check { get; set; } + public bool DisableFormat { get; set; } public CustomHttpMethodAttribute(string method, string template = null, bool check = true, int order = 1) : base(new List() { method }, $"[controller]{(template != null ? $"/{template}" : "")}") diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index ae2a18126a..c7152a576c 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -817,7 +817,7 @@ namespace ASC.Api.Documents /// File information /// Files /// File info - [Read("file/{fileId}")] + [Read("file/{fileId}", DisableFormat = true)] public FileWrapper GetFileInfo(string fileId, int version = -1) { var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs index 6083fdf849..84a4d44274 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/DaoFactory.cs @@ -77,6 +77,7 @@ namespace ASC.Files.Core.Data .AddTagDaoService() .AddSecurityDaoService() .AddCachedProviderAccountDaoService() + .AddProviderTagDaoService() .AddProviderSecurityDaoService() .AddProviderFileDaoService() .AddProviderFolderDaoService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index 41885ec135..757afb03fe 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -475,6 +475,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderFileDaoService(this DIHelper services) { services.TryAddScoped, ProviderFileDao>(); + services.TryAddScoped>(); return services .AddProviderDaoBaseService(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs index 955c1a5467..5ffb6d35c9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs @@ -348,6 +348,7 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); public static DIHelper AddProviderFolderDaoService(this DIHelper services) { services.TryAddScoped, ProviderFolderDao>(); + services.TryAddScoped>(); return services .AddProviderDaoBaseService(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs new file mode 100644 index 0000000000..659f85bda6 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs @@ -0,0 +1,136 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2018 + * + * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). + * In accordance with Section 7(a) of the GNU GPL 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 more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html + * + * You can contact Ascensio System SIA by email at sales@onlyoffice.com + * + * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display + * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. + * + * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains + * relevant author attributions when distributing the software. If the display of the logo in its graphic + * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" + * in every copy of the program you distribute. + * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. + * +*/ + + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Files.Core; +using ASC.Files.Core.Data; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; + +namespace ASC.Files.Thirdparty.ProviderDao +{ + internal class ProviderTagDao : ProviderDaoBase, ITagDao + { + public ProviderTagDao(IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, SetupInfo setupInfo, FileConverter fileConverter) : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + { + } + + public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) + { + return TagDao.GetTags(tagType, fileEntries); + } + + public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) + { + return GetSelector(parentFolder.ID) + .GetTagDao(parentFolder.ID) + .GetNewTags(subject, parentFolder, deepSearch); + } + + #region Only for Teamlab Documents + + public IEnumerable GetNewTags(Guid subject, IEnumerable> fileEntries) + { + return TagDao.GetNewTags(subject, fileEntries); + } + + public IEnumerable GetNewTags(Guid subject, FileEntry fileEntry) + { + return TagDao.GetNewTags(subject, fileEntry); + } + + public IEnumerable GetTags(Guid owner, TagType tagType) + { + return TagDao.GetTags(owner, tagType); + } + + public IEnumerable GetTags(string name, TagType tagType) + { + return TagDao.GetTags(name, tagType); + } + + public IEnumerable GetTags(string[] names, TagType tagType) + { + return TagDao.GetTags(names, tagType); + } + + + public IEnumerable SaveTags(IEnumerable tag) + { + return TagDao.SaveTags(tag); + } + + public IEnumerable SaveTags(Tag tag) + { + return TagDao.SaveTags(tag); + } + + public void UpdateNewTags(IEnumerable tag) + { + TagDao.UpdateNewTags(tag); + } + + public void UpdateNewTags(Tag tag) + { + TagDao.UpdateNewTags(tag); + } + + public void RemoveTags(IEnumerable tag) + { + TagDao.RemoveTags(tag); + } + + public void RemoveTags(Tag tag) + { + TagDao.RemoveTags(tag); + } + + public IEnumerable GetTags(string entryID, FileEntryType entryType, TagType tagType) + { + return TagDao.GetTags(entryID, entryType, tagType); + } + + #endregion + + public void Dispose() + { + } + } + + public static class ProviderTagDaoExtention + { + public static DIHelper AddProviderTagDaoService(this DIHelper services) + { + services.TryAddScoped, ProviderTagDao>(); + + return services + .AddProviderDaoBaseService(); + } + } +} \ No newline at end of file From 8f455e388fad57e662f3461a6611f9d0f34bcdb6 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Mon, 16 Mar 2020 18:34:51 +0300 Subject: [PATCH 15/30] Thirdparty: refactoring --- .../Core/Thirdparty/BaseProviderInfo.cs | 9 ++ .../Server/Core/Thirdparty/Box/BoxDaoBase.cs | 19 +-- .../Core/Thirdparty/Box/BoxDaoSelector.cs | 104 ++------------ .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 9 +- .../Thirdparty/Dropbox/DropboxDaoSelector.cs | 105 ++------------ .../GoogleDrive/GoogleDriveDaoBase.cs | 9 +- .../GoogleDrive/GoogleDriveDaoSelector.cs | 104 ++------------ .../Server/Core/Thirdparty/IDaoSelector.cs | 13 ++ .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 9 +- .../OneDrive/OneDriveDaoSelector.cs | 102 ++------------ .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 8 +- .../Thirdparty/ProviderDao/ProviderFileDao.cs | 3 +- .../Core/Thirdparty/RegexDaoSelectorBase.cs | 132 +++++++++++------- .../SharePoint/SharePointDaoBase.cs | 9 +- .../SharePoint/SharePointDaoSelector.cs | 77 ++-------- .../Thirdparty/Sharpbox/SharpBoxDaoBase.cs | 14 +- .../Sharpbox/SharpBoxDaoSelector.cs | 103 ++------------ .../Sharpbox/SharpBoxProviderInfo.cs | 17 --- 18 files changed, 233 insertions(+), 613 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/BaseProviderInfo.cs diff --git a/products/ASC.Files/Server/Core/Thirdparty/BaseProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/BaseProviderInfo.cs new file mode 100644 index 0000000000..5ebc2f78f0 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/BaseProviderInfo.cs @@ -0,0 +1,9 @@ +namespace ASC.Files.Core.Thirdparty +{ + public class BaseProviderInfo where T : IProviderInfo + { + public T ProviderInfo { get; set; } + public string Path { get; set; } + public string PathPrefix { get; set; } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs index 72f5a87a15..8d6960729e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs @@ -36,6 +36,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; @@ -47,9 +48,9 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Box { - internal abstract class BoxDaoBase + internal abstract class BoxDaoBase : IThirdPartyProviderDao { - public BoxDaoSelector BoxDaoSelector { get; set; } + public RegexDaoSelectorBase BoxDaoSelector { get; set; } public int TenantID { get; private set; } public BoxProviderInfo BoxProviderInfo { get; set; } @@ -75,13 +76,13 @@ namespace ASC.Files.Thirdparty.Box TenantUtil = tenantUtil; SetupInfo = setupInfo; } - - public void Init(BoxDaoSelector.BoxInfo boxInfo, BoxDaoSelector boxDaoSelector) - { - BoxProviderInfo = boxInfo.BoxProviderInfo; + + public void Init(BaseProviderInfo boxInfo, RegexDaoSelectorBase selectorBase) + { + BoxProviderInfo = boxInfo.ProviderInfo; PathPrefix = boxInfo.PathPrefix; - BoxDaoSelector = boxDaoSelector; - } + BoxDaoSelector = selectorBase; + } public void Dispose() { @@ -424,6 +425,6 @@ namespace ASC.Files.Thirdparty.Box var index = Convert.ToInt32(match.Groups[2].Value); var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); return string.Format(" ({0}){1}", index + 1, staticText); - } + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs index edaeabfeec..13eefcb03d 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs @@ -25,7 +25,6 @@ using System; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -35,93 +34,34 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Box { - internal class BoxDaoSelector : RegexDaoSelectorBase + internal class BoxDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } + protected internal override string Name { get => "Box"; } + protected internal override string Id { get => "box"; } - internal class BoxInfo - { - public BoxProviderInfo BoxProviderInfo { get; set; } - - public string Path { get; set; } - public string PathPrefix { get; set; } - } - public BoxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^box-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); + return base.GetFolderDao(id); + } - res.Init(GetInfo(id), this); - - return res; - } - - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; - } - - public override string ConvertId(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["path"].Value.Replace('|', '/'); - } - throw new ArgumentException("Id is not a Box id"); - } - return base.ConvertId(null); - } - - private BoxInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = objectId; - var match = Selector.Match(id); - if (match.Success) - { - var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - - return new BoxInfo - { - Path = match.Groups["path"].Value, - BoxProviderInfo = providerInfo, - PathPrefix = "box-" + match.Groups["id"].Value - }; - } - throw new ArgumentException("Id is not a Box id"); + return base.GetSecurityDao(id); } public override string GetIdCode(string id) @@ -137,23 +77,7 @@ namespace ASC.Files.Thirdparty.Box return base.GetIdCode(id); } - private BoxProviderInfo GetProviderInfo(int linkId) - { - BoxProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - try - { - info = (BoxProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(BoxProviderInfo boxProviderInfo, string newTitle) + public override void RenameProvider(BoxProviderInfo boxProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(boxProviderInfo.ID, newTitle, null, boxProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index b2f55f471e..eca69d0e54 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -36,6 +36,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; @@ -47,9 +48,9 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Dropbox { - internal abstract class DropboxDaoBase + internal abstract class DropboxDaoBase : IThirdPartyProviderDao { - protected DropboxDaoSelector DropboxDaoSelector { get; set; } + protected RegexDaoSelectorBase DropboxDaoSelector { get; set; } public int TenantID { get; private set; } public DropboxProviderInfo DropboxProviderInfo { get; private set; } @@ -76,9 +77,9 @@ namespace ASC.Files.Thirdparty.Dropbox FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); } - public void Init(DropboxDaoSelector.DropboxInfo dropboxInfo, DropboxDaoSelector dropboxDaoSelector) + public void Init(BaseProviderInfo dropboxInfo, RegexDaoSelectorBase dropboxDaoSelector) { - DropboxProviderInfo = dropboxInfo.DropboxProviderInfo; + DropboxProviderInfo = dropboxInfo.ProviderInfo; PathPrefix = dropboxInfo.PathPrefix; DropboxDaoSelector = dropboxDaoSelector; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs index 2230f7bc65..2783406645 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs @@ -26,7 +26,6 @@ using System; using System.Globalization; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -36,93 +35,34 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Dropbox { - internal class DropboxDaoSelector : RegexDaoSelectorBase + internal class DropboxDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } - - internal class DropboxInfo - { - public DropboxProviderInfo DropboxProviderInfo { get; set; } - - public string Path { get; set; } - public string PathPrefix { get; set; } - } + protected internal override string Name { get => "Dropbox"; } + protected internal override string Id { get => "dropbox"; } public DropboxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^dropbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFolderDao(id); } - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; - } - - public override string ConvertId(string id) - { - if (id != null) - { - var match = Selector.Match(Convert.ToString(id, CultureInfo.InvariantCulture)); - if (match.Success) - { - return match.Groups["path"].Value.Replace('|', '/'); - } - throw new ArgumentException("Id is not a Dropbox id"); - } - return base.ConvertId(null); - } - - private DropboxInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = Convert.ToString(objectId, CultureInfo.InvariantCulture); - var match = Selector.Match(id); - if (match.Success) - { - var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - - return new DropboxInfo - { - Path = match.Groups["path"].Value, - DropboxProviderInfo = providerInfo, - PathPrefix = "dropbox-" + match.Groups["id"].Value - }; - } - throw new ArgumentException("Id is not a Dropbox id"); + return base.GetSecurityDao(id); } public override string GetIdCode(string id) @@ -133,28 +73,13 @@ namespace ASC.Files.Thirdparty.Dropbox if (match.Success) { return match.Groups["id"].Value; - } + } + throw new ArgumentException("Id is not a Dropbox id"); } return base.GetIdCode(id); } - private DropboxProviderInfo GetProviderInfo(int linkId) - { - DropboxProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - try - { - info = (DropboxProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(DropboxProviderInfo dropboxProviderInfo, string newTitle) + public override void RenameProvider(DropboxProviderInfo dropboxProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(dropboxProviderInfo.ID, newTitle, null, dropboxProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs index a6ff8f463f..c475ec1fdd 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs @@ -38,6 +38,7 @@ using ASC.FederatedLogin.LoginProviders; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Core.Files; using ASC.Web.Files.Classes; @@ -50,9 +51,9 @@ using DriveFile = Google.Apis.Drive.v3.Data.File; namespace ASC.Files.Thirdparty.GoogleDrive { - internal abstract class GoogleDriveDaoBase + internal abstract class GoogleDriveDaoBase : IThirdPartyProviderDao { - public GoogleDriveDaoSelector GoogleDriveDaoSelector { get; set; } + public RegexDaoSelectorBase GoogleDriveDaoSelector { get; set; } public int TenantID { get; set; } public GoogleDriveProviderInfo GoogleDriveProviderInfo { get; set; } @@ -82,9 +83,9 @@ namespace ASC.Files.Thirdparty.GoogleDrive FileUtility = fileUtility; } - public void Init(GoogleDriveDaoSelector.GoogleDriveInfo googleDriveInfo, GoogleDriveDaoSelector googleDriveDaoSelector) + public void Init(BaseProviderInfo googleDriveInfo, RegexDaoSelectorBase googleDriveDaoSelector) { - GoogleDriveProviderInfo = googleDriveInfo.GoogleDriveProviderInfo; + GoogleDriveProviderInfo = googleDriveInfo.ProviderInfo; PathPrefix = googleDriveInfo.PathPrefix; GoogleDriveDaoSelector = googleDriveDaoSelector; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs index 59866b68a0..f48d99c5b5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs @@ -25,7 +25,6 @@ using System; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -35,93 +34,33 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.GoogleDrive { - internal class GoogleDriveDaoSelector : RegexDaoSelectorBase + internal class GoogleDriveDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } - - internal class GoogleDriveInfo - { - public GoogleDriveProviderInfo GoogleDriveProviderInfo { get; set; } - - public string Path { get; set; } - public string PathPrefix { get; set; } - } - + protected internal override string Name { get => "GoogleDrive"; } + protected internal override string Id { get => "drive"; } public GoogleDriveDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^drive-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFolderDao(id); } - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; - } - - public override string ConvertId(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["path"].Value.Replace('|', '/'); - } - throw new ArgumentException("Id is not a GoogleDrive id"); - } - return base.ConvertId(null); - } - - private GoogleDriveInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = objectId; - var match = Selector.Match(id); - if (match.Success) - { - var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - - return new GoogleDriveInfo - { - Path = match.Groups["path"].Value, - GoogleDriveProviderInfo = providerInfo, - PathPrefix = "drive-" + match.Groups["id"].Value - }; - } - throw new ArgumentException("Id is not a GoogleDrive id"); + return base.GetSecurityDao(id); } public override string GetIdCode(string id) @@ -137,24 +76,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive return base.GetIdCode(id); } - private GoogleDriveProviderInfo GetProviderInfo(int linkId) - { - GoogleDriveProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - - try - { - info = (GoogleDriveProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(GoogleDriveProviderInfo googleDriveProviderInfo, string newTitle) + public override void RenameProvider(GoogleDriveProviderInfo googleDriveProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(googleDriveProviderInfo.ID, newTitle, null, googleDriveProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs index d6a428eb63..6edbcb32f4 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs @@ -36,6 +36,19 @@ namespace ASC.Files.Thirdparty IFolderDao GetFolderDao(string id); ISecurityDao GetSecurityDao(string id); ITagDao GetTagDao(string id); + + string ConvertId(string id); + string GetIdCode(string id); + } + + internal interface IDaoSelector where T : class, IProviderInfo + { + bool IsMatch(string id); + IFileDao GetFileDao(string id) where T1 : IFileDao, IThirdPartyProviderDao; + IFolderDao GetFolderDao(string id) where T1 : IFolderDao, IThirdPartyProviderDao; + ISecurityDao GetSecurityDao(string id) where T1 : ISecurityDao, IThirdPartyProviderDao; + ITagDao GetTagDao(string id) where T1 : ITagDao, IThirdPartyProviderDao; + string ConvertId(string id); string GetIdCode(string id); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs index 555df1aa03..8c96c08236 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -35,6 +35,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; @@ -45,9 +46,9 @@ using Microsoft.OneDrive.Sdk; namespace ASC.Files.Thirdparty.OneDrive { - internal abstract class OneDriveDaoBase + internal abstract class OneDriveDaoBase : IThirdPartyProviderDao { - public OneDriveDaoSelector OneDriveDaoSelector { get; set; } + public RegexDaoSelectorBase OneDriveDaoSelector { get; set; } public int TenantID { get; private set; } public OneDriveProviderInfo OneDriveProviderInfo { get; set; } @@ -74,9 +75,9 @@ namespace ASC.Files.Thirdparty.OneDrive SetupInfo = setupInfo; } - public void Init(OneDriveDaoSelector.OneDriveInfo onedriveInfo, OneDriveDaoSelector onedriveDaoSelector) + public void Init(BaseProviderInfo onedriveInfo, RegexDaoSelectorBase onedriveDaoSelector) { - OneDriveProviderInfo = onedriveInfo.OneDriveProviderInfo; + OneDriveProviderInfo = onedriveInfo.ProviderInfo; PathPrefix = onedriveInfo.PathPrefix; OneDriveDaoSelector = onedriveDaoSelector; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs index f6d470a6ff..1ce8961b92 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs @@ -25,7 +25,6 @@ using System; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -35,93 +34,34 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.OneDrive { - internal class OneDriveDaoSelector : RegexDaoSelectorBase + internal class OneDriveDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } + protected internal override string Name { get => "OneDrive"; } + protected internal override string Id { get => "onedrive"; } - internal class OneDriveInfo - { - public OneDriveProviderInfo OneDriveProviderInfo { get; set; } - - public string Path { get; set; } - public string PathPrefix { get; set; } - } - public OneDriveDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^onedrive-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFolderDao(id); } - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; - } - - public override string ConvertId(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["path"].Value.Replace('|', '/'); - } - throw new ArgumentException("Id is not a OneDrive id"); - } - return base.ConvertId(null); - } - - private OneDriveInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = objectId; - var match = Selector.Match(id); - if (match.Success) - { - var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - - return new OneDriveInfo - { - Path = match.Groups["path"].Value, - OneDriveProviderInfo = providerInfo, - PathPrefix = "onedrive-" + match.Groups["id"].Value - }; - } - throw new ArgumentException("Id is not a OneDrive id"); + return base.GetSecurityDao(id); } public override string GetIdCode(string id) @@ -137,24 +77,8 @@ namespace ASC.Files.Thirdparty.OneDrive return base.GetIdCode(id); } - private OneDriveProviderInfo GetProviderInfo(int linkId) - { - OneDriveProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - try - { - info = (OneDriveProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(OneDriveProviderInfo onedriveProviderInfo, string newTitle) + public override void RenameProvider(OneDriveProviderInfo onedriveProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(onedriveProviderInfo.ID, newTitle, null, onedriveProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index 8778272c7a..81259351d0 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -46,7 +46,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.ProviderDao { - internal class ProviderDaoBase + internal class ProviderDaoBase : IDisposable { private readonly List Selectors; @@ -260,6 +260,12 @@ namespace ASC.Files.Thirdparty.ProviderDao return toFolderDao.GetFolder(toSelector.ConvertId(toFolderId)); } + + public void Dispose() + { + //TODO + //throw new NotImplementedException(); + } } public static class ProviderDaoBaseExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index 757afb03fe..d03fcef4b5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -40,7 +40,8 @@ namespace ASC.Files.Thirdparty.ProviderDao { internal class ProviderFileDao : ProviderDaoBase, IFileDao { - public ProviderFileDao(IServiceProvider serviceProvider, + public ProviderFileDao( + IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, SetupInfo setupInfo, diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs index ee10e89cb7..a10bb2d87e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -29,62 +29,41 @@ using System.Text.RegularExpressions; using ASC.Files.Core; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; + +using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty { - internal abstract class RegexDaoSelectorBase : IDaoSelector + internal abstract class RegexDaoSelectorBase : IDaoSelector, IDisposable where T : class, IProviderInfo { + public IServiceProvider ServiceProvider { get; } + public IDaoFactory DaoFactory { get; } public Regex Selector { get; set; } - public Func> FileDaoActivator { get; set; } - public Func> SecurityDaoActivator { get; set; } - public Func> FolderDaoActivator { get; set; } - public Func> TagDaoActivator { get; set; } - public Func IDConverter { get; set; } - - protected RegexDaoSelectorBase(Regex selector) - : this(selector, null, null, null, null) - { - } - - protected RegexDaoSelectorBase(Regex selector, - Func> fileDaoActivator, - Func> folderDaoActivator, - Func> securityDaoActivator, - Func> tagDaoActivator - ) - : this(selector, fileDaoActivator, folderDaoActivator, securityDaoActivator, tagDaoActivator, null) - { - } + protected internal abstract string Name { get; } + protected internal abstract string Id { get; } protected RegexDaoSelectorBase( - Regex selector, - Func> fileDaoActivator, - Func> folderDaoActivator, - Func> securityDaoActivator, - Func> tagDaoActivator, - Func idConverter) + IServiceProvider serviceProvider, + IDaoFactory daoFactory) { - Selector = selector ?? throw new ArgumentNullException("selector"); - FileDaoActivator = fileDaoActivator; - FolderDaoActivator = folderDaoActivator; - SecurityDaoActivator = securityDaoActivator; - TagDaoActivator = tagDaoActivator; - IDConverter = idConverter; + ServiceProvider = serviceProvider; + DaoFactory = daoFactory; + Selector = new Regex(@"^" + Id + @"-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled); } - public virtual ISecurityDao GetSecurityDao(string id) - { - return SecurityDaoActivator != null ? SecurityDaoActivator(id) : null; - } - - public virtual string ConvertId(string id) { try { if (id == null) return null; - return IDConverter != null ? IDConverter(id) : id; + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["path"].Value.Replace('|', '/'); + } + throw new ArgumentException($"Id is not a {Name} id"); } catch (Exception fe) { @@ -102,20 +81,79 @@ namespace ASC.Files.Thirdparty return id != null && Selector.IsMatch(id); } - - public virtual IFileDao GetFileDao(string id) + public virtual ISecurityDao GetSecurityDao(string id) where T1 : ISecurityDao, IThirdPartyProviderDao { - return FileDaoActivator != null ? FileDaoActivator(id) : null; + return GetDao(id); } - public virtual IFolderDao GetFolderDao(string id) + public virtual IFileDao GetFileDao(string id) where T1 : IFileDao, IThirdPartyProviderDao { - return FolderDaoActivator != null ? FolderDaoActivator(id) : null; + return GetDao(id); } - public virtual ITagDao GetTagDao(string id) + public virtual ITagDao GetTagDao(string id) where T1 : ITagDao, IThirdPartyProviderDao { - return TagDaoActivator != null ? TagDaoActivator(id) : null; + return GetDao(id); + } + + public virtual IFolderDao GetFolderDao(string id) where T1 : IFolderDao, IThirdPartyProviderDao + { + return GetDao(id); + } + + private T1 GetDao(string id) where T1 : IThirdPartyProviderDao + { + var res = ServiceProvider.GetService(); + + res.Init(GetInfo(id), this); + + return res; + } + + + internal BaseProviderInfo GetInfo(string objectId) + { + if (objectId == null) throw new ArgumentNullException("objectId"); + var id = objectId; + var match = Selector.Match(id); + if (match.Success) + { + var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); + + return new BaseProviderInfo + { + Path = match.Groups["path"].Value, + ProviderInfo = providerInfo, + PathPrefix = Id + "-" + match.Groups["id"].Value + }; + } + throw new ArgumentException($"Id is not {Name} id"); + } + + public abstract void RenameProvider(T provider, string newTitle); + + protected virtual T GetProviderInfo(int linkId) + { + var dbDao = DaoFactory.ProviderDao; + try + { + return dbDao.GetProviderInfo(linkId) as T; + } + catch (InvalidOperationException) + { + throw new ArgumentException("Provider id not found or you have no access"); + } + } + + public void Dispose() + { + //TODO + //throw new NotImplementedException(); } } + + internal interface IThirdPartyProviderDao where T : class, IProviderInfo + { + void Init(BaseProviderInfo t1, RegexDaoSelectorBase selectorBase); + } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs index f5e8c8ac93..030d91f8d9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs @@ -33,6 +33,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Studio.Core; @@ -42,10 +43,10 @@ using Folder = Microsoft.SharePoint.Client.Folder; namespace ASC.Files.Thirdparty.SharePoint { - internal class SharePointDaoBase + internal class SharePointDaoBase : IThirdPartyProviderDao { public SharePointProviderInfo ProviderInfo { get; private set; } - public SharePointDaoSelector SharePointDaoSelector { get; private set; } + public RegexDaoSelectorBase SharePointDaoSelector { get; private set; } public SharePointDaoBase( IServiceProvider serviceProvider, @@ -63,9 +64,9 @@ namespace ASC.Files.Thirdparty.SharePoint SetupInfo = setupInfo; } - public void Init(SharePointProviderInfo sharePointInfo, SharePointDaoSelector sharePointDaoSelector) + public void Init(BaseProviderInfo sharePointInfo, RegexDaoSelectorBase sharePointDaoSelector) { - ProviderInfo = sharePointInfo; + ProviderInfo = sharePointInfo.ProviderInfo; SharePointDaoSelector = sharePointDaoSelector; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs index af87606c78..b535f652ec 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs @@ -25,7 +25,6 @@ using System; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -35,52 +34,33 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.SharePoint { - internal class SharePointDaoSelector : RegexDaoSelectorBase + internal class SharePointDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } - + protected internal override string Name { get => "sharepoint"; } + protected internal override string Id { get => "spoint"; } public SharePointDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^spoint-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFolderDao(id); } - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetSecurityDao(id); } public override string ConvertId(string id) @@ -90,25 +70,13 @@ namespace ASC.Files.Thirdparty.SharePoint var match = Selector.Match(id); if (match.Success) { - return GetInfo(id).SpRootFolderId + match.Groups["path"].Value.Replace('|', '/'); + return GetInfo(id).ProviderInfo.SpRootFolderId + match.Groups["path"].Value.Replace('|', '/'); } throw new ArgumentException("Id is not a sharepoint id"); } return base.ConvertId(null); } - private SharePointProviderInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = objectId; - var match = Selector.Match(id); - if (match.Success) - { - return GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - } - throw new ArgumentException("Id is not a sharepoint id"); - } - public override string GetIdCode(string id) { if (id != null) @@ -122,24 +90,7 @@ namespace ASC.Files.Thirdparty.SharePoint return base.GetIdCode(id); } - private SharePointProviderInfo GetProviderInfo(int linkId) - { - SharePointProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - - try - { - info = (SharePointProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(SharePointProviderInfo sharePointProviderInfo, string newTitle) + public override void RenameProvider(SharePointProviderInfo sharePointProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(sharePointProviderInfo.ID, newTitle, null, sharePointProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs index 4f37a724bc..6fee5da664 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs @@ -41,6 +41,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Files.Core.Thirdparty; using ASC.Security.Cryptography; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; @@ -51,7 +52,7 @@ using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty.Sharpbox { - internal abstract class SharpBoxDaoBase : IDisposable + internal abstract class SharpBoxDaoBase : IThirdPartyProviderDao { protected class ErrorEntry : ICloudDirectoryEntry { @@ -168,18 +169,13 @@ namespace ASC.Files.Thirdparty.Sharpbox Log = monitor.CurrentValue; } - public void Init(SharpBoxDaoSelector.SharpBoxInfo sharpBoxInfo, SharpBoxDaoSelector sharpBoxDaoSelector) + public void Init(BaseProviderInfo sharpBoxInfo, RegexDaoSelectorBase sharpBoxDaoSelector) { - SharpBoxProviderInfo = sharpBoxInfo.SharpBoxProviderInfo; + SharpBoxProviderInfo = sharpBoxInfo.ProviderInfo; PathPrefix = sharpBoxInfo.PathPrefix; SharpBoxDaoSelector = sharpBoxDaoSelector; } - public void Dispose() - { - SharpBoxProviderInfo.Dispose(); - } - protected string MappingID(string id, bool saveIfNotExist) { if (id == null) return null; @@ -274,7 +270,7 @@ namespace ASC.Files.Thirdparty.Sharpbox } } - protected SharpBoxDaoSelector SharpBoxDaoSelector; + protected RegexDaoSelectorBase SharpBoxDaoSelector; public SharpBoxProviderInfo SharpBoxProviderInfo { get; set; } public string PathPrefix { get; private set; } public IServiceProvider ServiceProvider { get; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs index e88c4a3c3f..4ca06f8c45 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs @@ -25,7 +25,6 @@ using System; -using System.Text.RegularExpressions; using ASC.Common; using ASC.Files.Core; @@ -35,93 +34,34 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Sharpbox { - internal class SharpBoxDaoSelector : RegexDaoSelectorBase + internal class SharpBoxDaoSelector : RegexDaoSelectorBase, IDaoSelector { - public IServiceProvider ServiceProvider { get; } - public IDaoFactory DaoFactory { get; } - - internal class SharpBoxInfo - { - public SharpBoxProviderInfo SharpBoxProviderInfo { get; set; } - - public string Path { get; set; } - public string PathPrefix { get; set; } - } + protected internal override string Name { get => "SharpBox"; } + protected internal override string Id { get => "sbox"; } public SharpBoxDaoSelector(IServiceProvider serviceProvider, IDaoFactory daoFactory) - : base(new Regex(@"^sbox-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled)) + : base(serviceProvider, daoFactory) { - ServiceProvider = serviceProvider; - DaoFactory = daoFactory; } - public override IFileDao GetFileDao(string id) + public IFileDao GetFileDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFileDao(id); } - public override IFolderDao GetFolderDao(string id) + public IFolderDao GetFolderDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetFolderDao(id); } - public override ITagDao GetTagDao(string id) + public ITagDao GetTagDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; + return base.GetTagDao(id); } - public override ISecurityDao GetSecurityDao(string id) + public ISecurityDao GetSecurityDao(string id) { - var res = ServiceProvider.GetService(); - - res.Init(GetInfo(id), this); - - return res; - } - - public override string ConvertId(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["path"].Value.Replace('|', '/'); - } - throw new ArgumentException("Id is not a sharpbox id"); - } - return base.ConvertId(null); - } - - private SharpBoxInfo GetInfo(string objectId) - { - if (objectId == null) throw new ArgumentNullException("objectId"); - var id = objectId; - var match = Selector.Match(id); - if (match.Success) - { - var providerInfo = GetProviderInfo(Convert.ToInt32(match.Groups["id"].Value)); - - return new SharpBoxInfo - { - Path = match.Groups["path"].Value, - SharpBoxProviderInfo = providerInfo, - PathPrefix = "sbox-" + match.Groups["id"].Value - }; - } - throw new ArgumentException("Id is not a sharpbox id"); + return base.GetSecurityDao(id); } public override string GetIdCode(string id) @@ -137,24 +77,7 @@ namespace ASC.Files.Thirdparty.Sharpbox return base.GetIdCode(id); } - private SharpBoxProviderInfo GetProviderInfo(int linkId) - { - SharpBoxProviderInfo info; - - var dbDao = DaoFactory.ProviderDao; - - try - { - info = (SharpBoxProviderInfo)dbDao.GetProviderInfo(linkId); - } - catch (InvalidOperationException) - { - throw new ArgumentException("Provider id not found or you have no access"); - } - return info; - } - - public void RenameProvider(SharpBoxProviderInfo sharpBoxProviderInfo, string newTitle) + public override void RenameProvider(SharpBoxProviderInfo sharpBoxProviderInfo, string newTitle) { var dbDao = ServiceProvider.GetService(); dbDao.UpdateProviderInfo(sharpBoxProviderInfo.ID, newTitle, null, sharpBoxProviderInfo.RootFolderType); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs index 96cad0d038..e06700b05a 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -52,24 +52,7 @@ namespace ASC.Files.Thirdparty.Sharpbox Wrapper = storageDisposableWrapper; Log = monitor.CurrentValue; } - //public SharpBoxProviderInfo(int id, string providerKey, string customerTitle, AuthData authData, Guid owner, FolderType rootFolderType, DateTime createOn) - //{ - // if (string.IsNullOrEmpty(providerKey)) - // throw new ArgumentNullException("providerKey"); - // if (string.IsNullOrEmpty(authData.Token) && string.IsNullOrEmpty(authData.Password)) - // throw new ArgumentNullException("token", "Both token and password can't be null"); - // if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password) && string.IsNullOrEmpty(authData.Token)) - // throw new ArgumentNullException("password", "Password can't be null"); - // ID = id; - // CustomerTitle = customerTitle; - // Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner; - - // _providerKey = (nSupportedCloudConfigurations)Enum.Parse(typeof(nSupportedCloudConfigurations), providerKey, true); - // _authData = authData; - // RootFolderType = rootFolderType; - // CreateOn = createOn; - //} public void Dispose() { From ff36878397ad4a57f082dfc3bb12ff07f283d00f Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 17 Mar 2020 10:48:33 +0300 Subject: [PATCH 16/30] Files: thirdparty refactoring --- .../Core/Dao/Interfaces/IProviderInfo.cs | 1 + .../Server/Core/Thirdparty/Box/BoxDaoBase.cs | 7 +++- .../Core/Thirdparty/Box/BoxDaoSelector.cs | 23 +---------- .../Core/Thirdparty/Box/BoxProviderInfo.cs | 2 +- .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 7 +++- .../Thirdparty/Dropbox/DropboxDaoSelector.cs | 24 ----------- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 2 +- .../GoogleDrive/GoogleDriveDaoBase.cs | 5 ++- .../GoogleDrive/GoogleDriveDaoSelector.cs | 22 ---------- .../GoogleDrive/GoogleDriveProviderInfo.cs | 2 +- .../Server/Core/Thirdparty/IDaoSelector.cs | 4 +- .../Core/Thirdparty/IThirdPartyProviderDao.cs | 12 ++++++ .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 5 ++- .../OneDrive/OneDriveDaoSelector.cs | 23 ----------- .../OneDrive/OneDriveProviderInfo.cs | 3 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 3 +- .../Core/Thirdparty/RegexDaoSelectorBase.cs | 40 ++++++++++++++----- .../SharePoint/SharePointDaoBase.cs | 8 ++++ .../SharePoint/SharePointDaoSelector.cs | 22 ---------- .../SharePoint/SharePointProviderInfo.cs | 2 +- .../Thirdparty/Sharpbox/SharpBoxDaoBase.cs | 8 ++++ .../Sharpbox/SharpBoxDaoSelector.cs | 22 ---------- .../Sharpbox/SharpBoxProviderInfo.cs | 2 +- 23 files changed, 88 insertions(+), 161 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs index 4ebe0cbfcd..38ca1c773a 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs @@ -41,5 +41,6 @@ namespace ASC.Files.Core bool CheckAccess(); void InvalidateStorage(); + void UpdateTitle(string newtitle); } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs index 8d6960729e..ce5ff13c82 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs @@ -85,8 +85,11 @@ namespace ASC.Files.Thirdparty.Box } public void Dispose() - { - BoxProviderInfo.Dispose(); + { + if (BoxProviderInfo != null) + { + BoxProviderInfo.Dispose(); + } } protected string MappingID(string id, bool saveIfNotExist = false) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs index 13eefcb03d..6f5ddce7ef 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoSelector.cs @@ -29,8 +29,6 @@ using System; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; - -using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Box { @@ -63,27 +61,8 @@ namespace ASC.Files.Thirdparty.Box { return base.GetSecurityDao(id); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["id"].Value; - } - } - return base.GetIdCode(id); - } - - public override void RenameProvider(BoxProviderInfo boxProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(boxProviderInfo.ID, newTitle, null, boxProviderInfo.RootFolderType); - boxProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } + public static class BoxDaoSelectorExtention { public static DIHelper AddBoxDaoSelectorService(this DIHelper services) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs index 187d93f953..e25c1751bf 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -135,7 +135,7 @@ namespace ASC.Files.Thirdparty.Box CacheReset(); } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index eca69d0e54..b8bc40185f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -85,8 +85,11 @@ namespace ASC.Files.Thirdparty.Dropbox } public void Dispose() - { - DropboxProviderInfo.Dispose(); + { + if (DropboxProviderInfo != null) + { + DropboxProviderInfo.Dispose(); + } } protected string MappingID(string id, bool saveIfNotExist = false) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs index 2783406645..eb0c6ec714 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoSelector.cs @@ -25,13 +25,10 @@ using System; -using System.Globalization; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; - -using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Dropbox { @@ -64,27 +61,6 @@ namespace ASC.Files.Thirdparty.Dropbox { return base.GetSecurityDao(id); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(Convert.ToString(id, CultureInfo.InvariantCulture)); - if (match.Success) - { - return match.Groups["id"].Value; - } - throw new ArgumentException("Id is not a Dropbox id"); - } - return base.GetIdCode(id); - } - - public override void RenameProvider(DropboxProviderInfo dropboxProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(dropboxProviderInfo.ID, newTitle, null, dropboxProviderInfo.RootFolderType); - dropboxProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } public static class DropboxDaoSelectorExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index 09c5385ebe..60cafb10e7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -118,7 +118,7 @@ namespace ASC.Files.Thirdparty.Dropbox CacheReset(); } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs index c475ec1fdd..c586c03c9c 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs @@ -92,7 +92,10 @@ namespace ASC.Files.Thirdparty.GoogleDrive public void Dispose() { - GoogleDriveProviderInfo.Dispose(); + if (GoogleDriveProviderInfo != null) + { + GoogleDriveProviderInfo.Dispose(); + } } protected string MappingID(string id, bool saveIfNotExist = false) diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs index f48d99c5b5..0234362913 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoSelector.cs @@ -30,8 +30,6 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; -using Microsoft.Extensions.DependencyInjection; - namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveDaoSelector : RegexDaoSelectorBase, IDaoSelector @@ -62,26 +60,6 @@ namespace ASC.Files.Thirdparty.GoogleDrive { return base.GetSecurityDao(id); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["id"].Value; - } - } - return base.GetIdCode(id); - } - - public override void RenameProvider(GoogleDriveProviderInfo googleDriveProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(googleDriveProviderInfo.ID, newTitle, null, googleDriveProviderInfo.RootFolderType); - googleDriveProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } public static class GoogleDriveDaoSelectorExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index 61d0bc69fd..629297e385 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -148,7 +148,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive CacheReset(); } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs index 6edbcb32f4..730abe9d93 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs @@ -24,12 +24,14 @@ */ +using System; + using ASC.Files.Core; using ASC.Files.Core.Security; namespace ASC.Files.Thirdparty { - internal interface IDaoSelector + internal interface IDaoSelector : IDisposable { bool IsMatch(string id); IFileDao GetFileDao(string id); diff --git a/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs new file mode 100644 index 0000000000..37912850cf --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -0,0 +1,12 @@ +using System; + +using ASC.Files.Core; +using ASC.Files.Core.Thirdparty; + +namespace ASC.Files.Thirdparty +{ + internal interface IThirdPartyProviderDao : IDisposable where T : class, IProviderInfo + { + void Init(BaseProviderInfo t1, RegexDaoSelectorBase selectorBase); + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs index 8c96c08236..0743793bc7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -84,7 +84,10 @@ namespace ASC.Files.Thirdparty.OneDrive public void Dispose() { - OneDriveProviderInfo.Dispose(); + if (OneDriveProviderInfo != null) + { + OneDriveProviderInfo.Dispose(); + } } protected string MappingID(string id, bool saveIfNotExist = false) diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs index 1ce8961b92..12e5d81887 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoSelector.cs @@ -29,8 +29,6 @@ using System; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; - -using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.OneDrive { @@ -63,27 +61,6 @@ namespace ASC.Files.Thirdparty.OneDrive { return base.GetSecurityDao(id); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["id"].Value; - } - } - return base.GetIdCode(id); - } - - - public override void RenameProvider(OneDriveProviderInfo onedriveProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(onedriveProviderInfo.ID, newTitle, null, onedriveProviderInfo.RootFolderType); - onedriveProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } public static class OneDriveDaoSelectorExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index 1132cf4f04..8120a2c4a4 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -119,10 +119,11 @@ namespace ASC.Files.Thirdparty.OneDrive CacheReset(); } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } + internal Item GetOneDriveItem(string itemId) { return OneDriveProviderInfoHelper.GetOneDriveItem(Storage, ID, itemId); diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index 81259351d0..c83961b111 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -263,8 +263,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public void Dispose() { - //TODO - //throw new NotImplementedException(); + Selectors.ForEach(r => r.Dispose()); } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs index a10bb2d87e..c8513e6d74 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -25,6 +25,7 @@ using System; +using System.Collections.Generic; using System.Text.RegularExpressions; using ASC.Files.Core; @@ -35,7 +36,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty { - internal abstract class RegexDaoSelectorBase : IDaoSelector, IDisposable where T : class, IProviderInfo + internal abstract class RegexDaoSelectorBase : IDaoSelector where T : class, IProviderInfo { public IServiceProvider ServiceProvider { get; } public IDaoFactory DaoFactory { get; } @@ -43,6 +44,8 @@ namespace ASC.Files.Thirdparty protected internal abstract string Name { get; } protected internal abstract string Id { get; } + private Dictionary> Providers { get; set; } + protected RegexDaoSelectorBase( IServiceProvider serviceProvider, IDaoFactory daoFactory) @@ -50,6 +53,7 @@ namespace ASC.Files.Thirdparty ServiceProvider = serviceProvider; DaoFactory = daoFactory; Selector = new Regex(@"^" + Id + @"-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled); + Providers = new Dictionary>(); } public virtual string ConvertId(string id) @@ -71,9 +75,17 @@ namespace ASC.Files.Thirdparty } } - public virtual string GetIdCode(string id) + public string GetIdCode(string id) { - return null; + if (id != null) + { + var match = Selector.Match(id); + if (match.Success) + { + return match.Groups["id"].Value; + } + } + throw new ArgumentException($"Id is not a {Name} id"); } public virtual bool IsMatch(string id) @@ -103,10 +115,14 @@ namespace ASC.Files.Thirdparty private T1 GetDao(string id) where T1 : IThirdPartyProviderDao { + if (Providers.ContainsKey(id)) return (T1)Providers[id]; + var res = ServiceProvider.GetService(); res.Init(GetInfo(id), this); + Providers.Add(id, res); + return res; } @@ -130,7 +146,12 @@ namespace ASC.Files.Thirdparty throw new ArgumentException($"Id is not {Name} id"); } - public abstract void RenameProvider(T provider, string newTitle); + public void RenameProvider(T provider, string newTitle) + { + var dbDao = ServiceProvider.GetService(); + dbDao.UpdateProviderInfo(provider.ID, newTitle, null, provider.RootFolderType); + provider.UpdateTitle(newTitle); //This will update cached version too + } protected virtual T GetProviderInfo(int linkId) { @@ -147,13 +168,10 @@ namespace ASC.Files.Thirdparty public void Dispose() { - //TODO - //throw new NotImplementedException(); + foreach (var p in Providers) + { + p.Value.Dispose(); + } } } - - internal interface IThirdPartyProviderDao where T : class, IProviderInfo - { - void Init(BaseProviderInfo t1, RegexDaoSelectorBase selectorBase); - } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs index 030d91f8d9..e321decdde 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs @@ -207,5 +207,13 @@ namespace ASC.Files.Thirdparty.SharePoint { return MappingID(id, false); } + + public void Dispose() + { + if (ProviderInfo != null) + { + ProviderInfo.Dispose(); + } + } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs index b535f652ec..c76afc37d8 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoSelector.cs @@ -30,8 +30,6 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; -using Microsoft.Extensions.DependencyInjection; - namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointDaoSelector : RegexDaoSelectorBase, IDaoSelector @@ -76,26 +74,6 @@ namespace ASC.Files.Thirdparty.SharePoint } return base.ConvertId(null); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["id"].Value; - } - } - return base.GetIdCode(id); - } - - public override void RenameProvider(SharePointProviderInfo sharePointProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(sharePointProviderInfo.ID, newTitle, null, sharePointProviderInfo.RootFolderType); - sharePointProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } public static class SharePointDaoSelectorExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs index f22f938563..233209e588 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs @@ -95,7 +95,7 @@ namespace ASC.Files.Thirdparty.SharePoint SharePointProviderInfoHelper.Invalidate(); } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs index 6fee5da664..d077398713 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs @@ -571,5 +571,13 @@ namespace ASC.Files.Thirdparty.Sharpbox var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); return string.Format(" ({0}){1}", index + 1, staticText); } + + public void Dispose() + { + if (SharpBoxProviderInfo != null) + { + SharpBoxProviderInfo.Dispose(); + } + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs index 4ca06f8c45..5c23582386 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoSelector.cs @@ -30,8 +30,6 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Security; -using Microsoft.Extensions.DependencyInjection; - namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxDaoSelector : RegexDaoSelectorBase, IDaoSelector @@ -63,26 +61,6 @@ namespace ASC.Files.Thirdparty.Sharpbox { return base.GetSecurityDao(id); } - - public override string GetIdCode(string id) - { - if (id != null) - { - var match = Selector.Match(id); - if (match.Success) - { - return match.Groups["id"].Value; - } - } - return base.GetIdCode(id); - } - - public override void RenameProvider(SharpBoxProviderInfo sharpBoxProviderInfo, string newTitle) - { - var dbDao = ServiceProvider.GetService(); - dbDao.UpdateProviderInfo(sharpBoxProviderInfo.ID, newTitle, null, sharpBoxProviderInfo.RootFolderType); - sharpBoxProviderInfo.UpdateTitle(newTitle); //This will update cached version too - } } public static class SharpBoxDaoSelectorExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs index e06700b05a..03e70257db 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -79,7 +79,7 @@ namespace ASC.Files.Thirdparty.Sharpbox get => Wrapper.Storage != null && Wrapper.Storage.IsOpened; } - internal void UpdateTitle(string newtitle) + public void UpdateTitle(string newtitle) { CustomerTitle = newtitle; } From fad1f8255cce4041f748810de19d8b04de76fdfa Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 17 Mar 2020 15:49:14 +0300 Subject: [PATCH 17/30] Files: thirdparty --- .../Core/Dao/Interfaces/IProviderInfo.cs | 2 +- .../Server/Core/Thirdparty/Box/BoxDaoBase.cs | 170 +++------------- .../Server/Core/Thirdparty/Box/BoxFileDao.cs | 58 +++--- .../Core/Thirdparty/Box/BoxFolderDao.cs | 48 ++--- .../Core/Thirdparty/Box/BoxProviderInfo.cs | 2 +- .../Core/Thirdparty/Box/BoxSecurityDao.cs | 6 +- .../Server/Core/Thirdparty/Box/BoxTagDao.cs | 8 +- .../Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 167 +++------------- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 72 ++++--- .../Thirdparty/Dropbox/DropboxFolderDao.cs | 56 +++--- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 2 +- .../Thirdparty/Dropbox/DropboxSecurityDao.cs | 17 +- .../Core/Thirdparty/Dropbox/DropboxTagDao.cs | 9 +- .../GoogleDrive/GoogleDriveDaoBase.cs | 172 ++-------------- .../GoogleDrive/GoogleDriveFileDao.cs | 59 +++--- .../GoogleDrive/GoogleDriveFolderDao.cs | 48 ++--- .../GoogleDrive/GoogleDriveProviderInfo.cs | 2 +- .../GoogleDrive/GoogleDriveSecurityDao.cs | 5 +- .../GoogleDrive/GoogleDriveTagDao.cs | 9 +- .../Server/Core/Thirdparty/IDaoSelector.cs | 8 +- .../Core/Thirdparty/IThirdPartyProviderDao.cs | 183 +++++++++++++++++- .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 155 ++------------- .../Thirdparty/OneDrive/OneDriveFileDao.cs | 65 +++---- .../Thirdparty/OneDrive/OneDriveFolderDao.cs | 51 +++-- .../OneDrive/OneDriveProviderInfo.cs | 2 +- .../OneDrive/OneDriveSecurityDao.cs | 13 +- .../Thirdparty/OneDrive/OneDriveTagDao.cs | 16 +- .../Core/Thirdparty/RegexDaoSelectorBase.cs | 14 +- .../SharePoint/SharePointDaoBase.cs | 85 +------- .../SharePoint/SharePointFileDao.cs | 14 +- .../SharePoint/SharePointFolderDao.cs | 13 +- .../SharePoint/SharePointProviderInfo.cs | 2 +- .../SharePoint/SharePointSecurityDao.cs | 11 +- .../Thirdparty/SharePoint/SharePointTagDao.cs | 13 +- .../Thirdparty/Sharpbox/SharpBoxDaoBase.cs | 174 +++-------------- .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 28 +-- .../Thirdparty/Sharpbox/SharpBoxFolderDao.cs | 27 +-- .../Sharpbox/SharpBoxProviderInfo.cs | 2 +- .../Sharpbox/SharpBoxSecurityDao.cs | 3 +- .../Thirdparty/Sharpbox/SharpBoxTagDao.cs | 5 +- 40 files changed, 645 insertions(+), 1151 deletions(-) diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs index 38ca1c773a..93681c7d2a 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IProviderInfo.cs @@ -28,7 +28,7 @@ using System; namespace ASC.Files.Core { - public interface IProviderInfo + public interface IProviderInfo : IDisposable { int ID { get; set; } string ProviderKey { get; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs index ce5ff13c82..1c426d8de1 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs @@ -30,102 +30,28 @@ using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Security; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; +using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; using Box.V2.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty.Box { - internal abstract class BoxDaoBase : IThirdPartyProviderDao - { - public RegexDaoSelectorBase BoxDaoSelector { get; set; } - - public int TenantID { get; private set; } - public BoxProviderInfo BoxProviderInfo { get; set; } - public string PathPrefix { get; private set; } - public FilesDbContext FilesDbContext { get; } - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - public TenantUtil TenantUtil { get; } - public SetupInfo SetupInfo { get; } + internal abstract class BoxDaoBase : ThirdPartyProviderDao + { + public override string Id { get => "box"; } - public BoxDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) + public BoxDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - TenantID = tenantManager.GetCurrentTenant().TenantId; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - SetupInfo = setupInfo; - } - - public void Init(BaseProviderInfo boxInfo, RegexDaoSelectorBase selectorBase) - { - BoxProviderInfo = boxInfo.ProviderInfo; - PathPrefix = boxInfo.PathPrefix; - BoxDaoSelector = selectorBase; - } - - public void Dispose() - { - if (BoxProviderInfo != null) - { - BoxProviderInfo.Dispose(); - } - } - - protected string MappingID(string id, bool saveIfNotExist = false) - { - if (id == null) return null; - - string result; - if (id.StartsWith("box")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - return result; - } - - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); } @@ -155,18 +81,16 @@ namespace ASC.Files.Thirdparty.Box return MakeId(path); } - protected string MakeId(string path = null) + protected override string MakeId(string path = null) { - return string.Format("{0}{1}", PathPrefix, - string.IsNullOrEmpty(path) || path == "0" - ? "" : ("-|" + path.TrimStart('/'))); + return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "0" ? "" : ("-|" + path.TrimStart('/'))); } protected string MakeFolderTitle(BoxFolder boxFolder) { if (boxFolder == null || IsRoot(boxFolder)) { - return BoxProviderInfo.CustomerTitle; + return ProviderInfo.CustomerTitle; } return Global.ReplaceInvalidCharsAndTruncate(boxFolder.Name); @@ -176,7 +100,7 @@ namespace ASC.Files.Thirdparty.Box { if (boxFile == null || string.IsNullOrEmpty(boxFile.Name)) { - return BoxProviderInfo.ProviderKey; + return ProviderInfo.ProviderKey; } return Global.ReplaceInvalidCharsAndTruncate(boxFile.Name); @@ -193,22 +117,13 @@ namespace ASC.Files.Thirdparty.Box var isRoot = IsRoot(boxFolder); - var folder = ServiceProvider.GetService>(); + var folder = GetFolder(); folder.ID = MakeId(boxFolder.Id); folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(boxFolder)); - folder.CreateBy = BoxProviderInfo.Owner; - folder.CreateOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.CreatedAt ?? default); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = BoxProviderInfo.Owner; - folder.ModifiedOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.ModifiedAt ?? default); - folder.ProviderId = BoxProviderInfo.ID; - folder.ProviderKey = BoxProviderInfo.ProviderKey; - folder.RootFolderCreator = BoxProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = BoxProviderInfo.RootFolderType; + folder.CreateOn = isRoot ? ProviderInfo.CreateOn : (boxFolder.CreatedAt ?? default); + folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : (boxFolder.ModifiedAt ?? default); - folder.Shareable = false; folder.Title = MakeFolderTitle(boxFolder); folder.TotalFiles = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFile) : 0; folder.TotalSubFolders = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFolder) : 0; @@ -230,20 +145,10 @@ namespace ASC.Files.Thirdparty.Box private File ToErrorFile(ErrorFile boxFile) { if (boxFile == null) return null; - var file = ServiceProvider.GetService>(); - file.ID = MakeId(boxFile.ErrorId); - file.CreateBy = BoxProviderInfo.Owner; - file.CreateOn = TenantUtil.DateTimeNow(); - file.ModifiedBy = BoxProviderInfo.Owner; - file.ModifiedOn = TenantUtil.DateTimeNow(); - file.ProviderId = BoxProviderInfo.ID; - file.ProviderKey = BoxProviderInfo.ProviderKey; - file.RootFolderCreator = BoxProviderInfo.Owner; - file.RootFolderId = MakeId(); - file.RootFolderType = BoxProviderInfo.RootFolderType; + var file = GetErrorFile(new ErrorEntry(boxFile.Error, boxFile.ErrorId)); + file.Title = MakeFileTitle(boxFile); - file.Error = boxFile.Error; return file; } @@ -252,25 +157,9 @@ namespace ASC.Files.Thirdparty.Box { if (boxFolder == null) return null; - var folder = ServiceProvider.GetService>(); + var folder = GetErrorFolder(new ErrorEntry(boxFolder.Error, boxFolder.ErrorId)); - folder.ID = MakeId(boxFolder.ErrorId); - folder.ParentFolderID = null; - folder.CreateBy = BoxProviderInfo.Owner; - folder.CreateOn = TenantUtil.DateTimeNow(); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = BoxProviderInfo.Owner; - folder.ModifiedOn = TenantUtil.DateTimeNow(); - folder.ProviderId = BoxProviderInfo.ID; - folder.ProviderKey = BoxProviderInfo.ProviderKey; - folder.RootFolderCreator = BoxProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = BoxProviderInfo.RootFolderType; - folder.Shareable = false; folder.Title = MakeFolderTitle(boxFolder); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; - folder.Error = boxFolder.Error; return folder; } @@ -285,26 +174,15 @@ namespace ASC.Files.Thirdparty.Box return ToErrorFile(boxFile as ErrorFile); } - var file = ServiceProvider.GetService>(); + var file = GetFile(); file.ID = MakeId(boxFile.Id); - file.Access = FileShare.None; file.ContentLength = boxFile.Size.HasValue ? (long)boxFile.Size : 0; - file.CreateBy = BoxProviderInfo.Owner; file.CreateOn = boxFile.CreatedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.CreatedAt.Value) : default; - file.FileStatus = FileStatus.None; file.FolderID = MakeId(GetParentFolderId(boxFile)); - file.ModifiedBy = BoxProviderInfo.Owner; file.ModifiedOn = boxFile.ModifiedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.ModifiedAt.Value) : default; file.NativeAccessor = boxFile; - file.ProviderId = BoxProviderInfo.ID; - file.ProviderKey = BoxProviderInfo.ProviderKey; file.Title = MakeFileTitle(boxFile); - file.RootFolderId = MakeId(); - file.RootFolderType = BoxProviderInfo.RootFolderType; - file.RootFolderCreator = BoxProviderInfo.Owner; - file.Shared = false; - file.Version = 1; return file; } @@ -314,12 +192,12 @@ namespace ASC.Files.Thirdparty.Box return ToFolder(GetBoxFolder("0")); } - protected BoxFolder GetBoxFolder(object folderId) + protected BoxFolder GetBoxFolder(string folderId) { var boxFolderId = MakeBoxId(folderId); try { - var folder = BoxProviderInfo.GetBoxFolder(boxFolderId); + var folder = ProviderInfo.GetBoxFolder(boxFolderId); return folder; } catch (Exception ex) @@ -333,7 +211,7 @@ namespace ASC.Files.Thirdparty.Box var boxFileId = MakeBoxId(fileId); try { - var file = BoxProviderInfo.GetBoxFile(boxFileId); + var file = ProviderInfo.GetBoxFile(boxFileId); return file; } catch (Exception ex) @@ -342,15 +220,15 @@ namespace ASC.Files.Thirdparty.Box } } - protected IEnumerable GetChildren(object folderId) + protected IEnumerable GetChildren(string folderId) { return GetBoxItems(folderId).Select(entry => MakeId(entry.Id)); } - protected List GetBoxItems(object parentId, bool? folder = null) + protected List GetBoxItems(string parentId, bool? folder = null) { var boxFolderId = MakeBoxId(parentId); - var items = BoxProviderInfo.GetBoxItems(boxFolderId); + var items = ProviderInfo.GetBoxItems(boxFolderId); if (folder.HasValue) { diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs index 795411240a..c30b67b08b 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -42,29 +43,24 @@ using ASC.Web.Studio.Core; using Box.V2.Models; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Box { internal class BoxFileDao : BoxDaoBase, IFileDao { - public BoxFileDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public BoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } public void InvalidateCache(string fileId) { var boxFileId = MakeBoxId(fileId); - BoxProviderInfo.CacheReset(boxFileId, true); + ProviderInfo.CacheReset(boxFileId, true); var boxFile = GetBoxFile(fileId); var parentPath = GetParentFolderId(boxFile); - if (parentPath != null) BoxProviderInfo.CacheReset(parentPath); + if (parentPath != null) ProviderInfo.CacheReset(parentPath); } public File GetFile(string fileId) @@ -238,13 +234,13 @@ namespace ASC.Files.Thirdparty.Box public Stream GetFileStream(File file, long offset) { var boxFileId = MakeBoxId(file.ID); - BoxProviderInfo.CacheReset(boxFileId, true); + ProviderInfo.CacheReset(boxFileId, true); var boxFile = GetBoxFile(file.ID); if (boxFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); if (boxFile is ErrorFile) throw new Exception(((ErrorFile)boxFile).Error); - var fileStream = BoxProviderInfo.Storage.DownloadStream(boxFile, (int)offset); + var fileStream = ProviderInfo.Storage.DownloadStream(boxFile, (int)offset); return fileStream; } @@ -269,25 +265,25 @@ namespace ASC.Files.Thirdparty.Box if (file.ID != null) { var fileId = MakeBoxId(file.ID); - newBoxFile = BoxProviderInfo.Storage.SaveStream(fileId, fileStream); + newBoxFile = ProviderInfo.Storage.SaveStream(fileId, fileStream); if (!newBoxFile.Name.Equals(file.Title)) { var folderId = GetParentFolderId(GetBoxFile(fileId)); file.Title = GetAvailableTitle(file.Title, folderId, IsExist); - newBoxFile = BoxProviderInfo.Storage.RenameFile(fileId, file.Title); + newBoxFile = ProviderInfo.Storage.RenameFile(fileId, file.Title); } } else if (file.FolderID != null) { var folderId = MakeBoxId(file.FolderID); file.Title = GetAvailableTitle(file.Title, folderId, IsExist); - newBoxFile = BoxProviderInfo.Storage.CreateFile(fileStream, file.Title, folderId); + newBoxFile = ProviderInfo.Storage.CreateFile(fileStream, file.Title, folderId); } - BoxProviderInfo.CacheReset(newBoxFile); + ProviderInfo.CacheReset(newBoxFile); var parentId = GetParentFolderId(newBoxFile); - if (parentId != null) BoxProviderInfo.CacheReset(parentId); + if (parentId != null) ProviderInfo.CacheReset(parentId); return ToFile(newBoxFile); } @@ -339,17 +335,17 @@ namespace ASC.Files.Thirdparty.Box if (!(boxFile is ErrorFile)) { - BoxProviderInfo.Storage.DeleteItem(boxFile); + ProviderInfo.Storage.DeleteItem(boxFile); } - BoxProviderInfo.CacheReset(boxFile.Id, true); + ProviderInfo.CacheReset(boxFile.Id, true); var parentFolderId = GetParentFolderId(boxFile); - if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); } public bool IsExist(string title, object folderId) { - return GetBoxItems(folderId, false) + return GetBoxItems(folderId.ToString(), false) .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); } @@ -364,11 +360,11 @@ namespace ASC.Files.Thirdparty.Box var fromFolderId = GetParentFolderId(boxFile); var newTitle = GetAvailableTitle(boxFile.Name, toBoxFolder.Id, IsExist); - boxFile = BoxProviderInfo.Storage.MoveFile(boxFile.Id, newTitle, toBoxFolder.Id); + boxFile = ProviderInfo.Storage.MoveFile(boxFile.Id, newTitle, toBoxFolder.Id); - BoxProviderInfo.CacheReset(boxFile.Id, true); - BoxProviderInfo.CacheReset(fromFolderId); - BoxProviderInfo.CacheReset(toBoxFolder.Id); + ProviderInfo.CacheReset(boxFile.Id, true); + ProviderInfo.CacheReset(fromFolderId); + ProviderInfo.CacheReset(toBoxFolder.Id); return MakeId(boxFile.Id); } @@ -382,10 +378,10 @@ namespace ASC.Files.Thirdparty.Box if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); var newTitle = GetAvailableTitle(boxFile.Name, toBoxFolder.Id, IsExist); - var newBoxFile = BoxProviderInfo.Storage.CopyFile(boxFile.Id, newTitle, toBoxFolder.Id); + var newBoxFile = ProviderInfo.Storage.CopyFile(boxFile.Id, newTitle, toBoxFolder.Id); - BoxProviderInfo.CacheReset(newBoxFile); - BoxProviderInfo.CacheReset(toBoxFolder.Id); + ProviderInfo.CacheReset(newBoxFile); + ProviderInfo.CacheReset(toBoxFolder.Id); return ToFile(newBoxFile); } @@ -395,11 +391,11 @@ namespace ASC.Files.Thirdparty.Box var boxFile = GetBoxFile(file.ID); newTitle = GetAvailableTitle(newTitle, GetParentFolderId(boxFile), IsExist); - boxFile = BoxProviderInfo.Storage.RenameFile(boxFile.Id, newTitle); + boxFile = ProviderInfo.Storage.RenameFile(boxFile.Id, newTitle); - BoxProviderInfo.CacheReset(boxFile); + ProviderInfo.CacheReset(boxFile); var parentId = GetParentFolderId(boxFile); - if (parentId != null) BoxProviderInfo.CacheReset(parentId); + if (parentId != null) ProviderInfo.CacheReset(parentId); return MakeId(boxFile.Id); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs index 0b8d6b2a99..74ebc638fe 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs @@ -30,20 +30,24 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; using Box.V2.Models; - + +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Box { internal class BoxFolderDao : BoxDaoBase, IFolderDao { - public BoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public BoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -172,11 +176,11 @@ namespace ASC.Files.Thirdparty.Box folder.Title = GetAvailableTitle(folder.Title, boxFolderId, IsExist); - var boxFolder = BoxProviderInfo.Storage.CreateFolder(folder.Title, boxFolderId); + var boxFolder = ProviderInfo.Storage.CreateFolder(folder.Title, boxFolderId); - BoxProviderInfo.CacheReset(boxFolder); + ProviderInfo.CacheReset(boxFolder); var parentFolderId = GetParentFolderId(boxFolder); - if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); return MakeId(boxFolder); } @@ -230,12 +234,12 @@ namespace ASC.Files.Thirdparty.Box if (!(boxFolder is ErrorFolder)) { - BoxProviderInfo.Storage.DeleteItem(boxFolder); + ProviderInfo.Storage.DeleteItem(boxFolder); } - BoxProviderInfo.CacheReset(boxFolder.Id, true); + ProviderInfo.CacheReset(boxFolder.Id, true); var parentFolderId = GetParentFolderId(boxFolder); - if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) @@ -249,11 +253,11 @@ namespace ASC.Files.Thirdparty.Box var fromFolderId = GetParentFolderId(boxFolder); var newTitle = GetAvailableTitle(boxFolder.Name, toBoxFolder.Id, IsExist); - boxFolder = BoxProviderInfo.Storage.MoveFolder(boxFolder.Id, newTitle, toBoxFolder.Id); + boxFolder = ProviderInfo.Storage.MoveFolder(boxFolder.Id, newTitle, toBoxFolder.Id); - BoxProviderInfo.CacheReset(boxFolder.Id, false); - BoxProviderInfo.CacheReset(fromFolderId); - BoxProviderInfo.CacheReset(toBoxFolder.Id); + ProviderInfo.CacheReset(boxFolder.Id, false); + ProviderInfo.CacheReset(fromFolderId); + ProviderInfo.CacheReset(toBoxFolder.Id); return MakeId(boxFolder.Id); } @@ -267,11 +271,11 @@ namespace ASC.Files.Thirdparty.Box if (toBoxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toBoxFolder).Error); var newTitle = GetAvailableTitle(boxFolder.Name, toBoxFolder.Id, IsExist); - var newBoxFolder = BoxProviderInfo.Storage.CopyFolder(boxFolder.Id, newTitle, toBoxFolder.Id); + var newBoxFolder = ProviderInfo.Storage.CopyFolder(boxFolder.Id, newTitle, toBoxFolder.Id); - BoxProviderInfo.CacheReset(newBoxFolder); - BoxProviderInfo.CacheReset(newBoxFolder.Id, false); - BoxProviderInfo.CacheReset(toBoxFolder.Id); + ProviderInfo.CacheReset(newBoxFolder); + ProviderInfo.CacheReset(newBoxFolder.Id, false); + ProviderInfo.CacheReset(toBoxFolder.Id); return ToFolder(newBoxFolder); } @@ -289,7 +293,7 @@ namespace ASC.Files.Thirdparty.Box if (IsRoot(boxFolder)) { //It's root folder - BoxDaoSelector.RenameProvider(BoxProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else @@ -297,11 +301,11 @@ namespace ASC.Files.Thirdparty.Box newTitle = GetAvailableTitle(newTitle, parentFolderId, IsExist); //rename folder - boxFolder = BoxProviderInfo.Storage.RenameFolder(boxFolder.Id, newTitle); + boxFolder = ProviderInfo.Storage.RenameFolder(boxFolder.Id, newTitle); } - BoxProviderInfo.CacheReset(boxFolder); - if (parentFolderId != null) BoxProviderInfo.CacheReset(parentFolderId); + ProviderInfo.CacheReset(boxFolder); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); return MakeId(boxFolder.Id); } @@ -315,7 +319,7 @@ namespace ASC.Files.Thirdparty.Box { var boxFolderId = MakeBoxId(folderId); //note: without cache - return BoxProviderInfo.Storage.GetItems(boxFolderId, 1).Count == 0; + return ProviderInfo.Storage.GetItems(boxFolderId, 1).Count == 0; } public bool UseTrashForRemove(Folder folder) @@ -335,7 +339,7 @@ namespace ASC.Files.Thirdparty.Box public long GetMaxUploadSize(string folderId, bool chunkedUpload) { - var storageMaxUploadSize = BoxProviderInfo.Storage.GetMaxUploadSize(); + var storageMaxUploadSize = ProviderInfo.Storage.GetMaxUploadSize(); return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs index e25c1751bf..bfb6912075 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -44,7 +44,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Thirdparty.Box { [DebuggerDisplay("{CustomerTitle}")] - internal class BoxProviderInfo : IProviderInfo, IDisposable + internal class BoxProviderInfo : IProviderInfo { public OAuth20Token Token { get; set; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs index 0e21941e4d..0d70cd910d 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxSecurityDao.cs @@ -28,19 +28,23 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Box { internal class BoxSecurityDao : BoxDaoBase, ISecurityDao { - public BoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public BoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs index 0b78f8a8df..e2fb5c7ba0 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxTagDao.cs @@ -29,19 +29,23 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Box { internal class BoxTagDao : BoxDaoBase, ITagDao { - public BoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public BoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -69,7 +73,7 @@ namespace ASC.Files.Thirdparty.Box public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = BoxDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); var entryIDs = FilesDbContext.ThirdpartyIdMapping diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index b8bc40185f..9b7819f79e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -30,105 +30,30 @@ using System.Globalization; using System.Linq; using System.Text.RegularExpressions; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Security; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; +using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; using Dropbox.Api.Files; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty.Dropbox { - internal abstract class DropboxDaoBase : IThirdPartyProviderDao - { - protected RegexDaoSelectorBase DropboxDaoSelector { get; set; } - - public int TenantID { get; private set; } - public DropboxProviderInfo DropboxProviderInfo { get; private set; } - public string PathPrefix { get; private set; } - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - public TenantUtil TenantUtil { get; } - public SetupInfo SetupInfo { get; } - public FilesDbContext FilesDbContext { get; } + internal abstract class DropboxDaoBase : ThirdPartyProviderDao + { + public override string Id { get => "dropbox"; } - public DropboxDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) + public DropboxDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - SetupInfo = setupInfo; - TenantID = tenantManager.GetCurrentTenant().TenantId; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - } - - public void Init(BaseProviderInfo dropboxInfo, RegexDaoSelectorBase dropboxDaoSelector) - { - DropboxProviderInfo = dropboxInfo.ProviderInfo; - PathPrefix = dropboxInfo.PathPrefix; - DropboxDaoSelector = dropboxDaoSelector; - } - - public void Dispose() - { - if (DropboxProviderInfo != null) - { - DropboxProviderInfo.Dispose(); - } - } - - protected string MappingID(string id, bool saveIfNotExist = false) - { - if (id == null) return null; - - string result; - if (id.StartsWith("dropbox")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id, HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - return result; } - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); - } - - protected static string GetParentFolderPath(Metadata dropboxItem) { if (dropboxItem == null || IsRoot(dropboxItem.AsFolder)) @@ -159,7 +84,7 @@ namespace ASC.Files.Thirdparty.Dropbox return MakeId(MakeDropboxPath(dropboxItem)); } - protected string MakeId(string path = null) + protected override string MakeId(string path = null) { return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "/" ? "" : ("-" + path.Replace('/', '|'))); } @@ -168,7 +93,7 @@ namespace ASC.Files.Thirdparty.Dropbox { if (dropboxFolder == null || IsRoot(dropboxFolder)) { - return DropboxProviderInfo.CustomerTitle; + return ProviderInfo.CustomerTitle; } return Global.ReplaceInvalidCharsAndTruncate(dropboxFolder.Name); @@ -178,7 +103,7 @@ namespace ASC.Files.Thirdparty.Dropbox { if (dropboxFile == null || string.IsNullOrEmpty(dropboxFile.Name)) { - return DropboxProviderInfo.ProviderKey; + return ProviderInfo.ProviderKey; } return Global.ReplaceInvalidCharsAndTruncate(dropboxFile.Name); @@ -195,24 +120,13 @@ namespace ASC.Files.Thirdparty.Dropbox var isRoot = IsRoot(dropboxFolder); - var folder = ServiceProvider.GetService>(); + var folder = GetFolder(); folder.ID = MakeId(dropboxFolder); folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderPath(dropboxFolder)); - folder.CreateBy = DropboxProviderInfo.Owner; - folder.CreateOn = isRoot ? DropboxProviderInfo.CreateOn : default; - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = DropboxProviderInfo.Owner; - folder.ModifiedOn = isRoot ? DropboxProviderInfo.CreateOn : default; - folder.ProviderId = DropboxProviderInfo.ID; - folder.ProviderKey = DropboxProviderInfo.ProviderKey; - folder.RootFolderCreator = DropboxProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = DropboxProviderInfo.RootFolderType; - folder.Shareable = false; - folder.Title = MakeFolderTitle(dropboxFolder); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; + folder.CreateOn = isRoot ? ProviderInfo.CreateOn : default; + folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : default; + folder.Title = MakeFolderTitle(dropboxFolder); if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); @@ -231,19 +145,10 @@ namespace ASC.Files.Thirdparty.Dropbox private File ToErrorFile(ErrorFile dropboxFile) { if (dropboxFile == null) return null; - var file = ServiceProvider.GetService>(); - file.ID = MakeId(dropboxFile.ErrorId); - file.CreateBy = DropboxProviderInfo.Owner; - file.CreateOn = TenantUtil.DateTimeNow(); - file.ModifiedBy = DropboxProviderInfo.Owner; - file.ModifiedOn = TenantUtil.DateTimeNow(); - file.ProviderId = DropboxProviderInfo.ID; - file.ProviderKey = DropboxProviderInfo.ProviderKey; - file.RootFolderCreator = DropboxProviderInfo.Owner; - file.RootFolderId = MakeId(); - file.RootFolderType = DropboxProviderInfo.RootFolderType; + + var file = GetErrorFile(new ErrorEntry(dropboxFile.ErrorId, dropboxFile.Error)); + file.Title = MakeFileTitle(dropboxFile); - file.Error = dropboxFile.Error; return file; } @@ -251,25 +156,10 @@ namespace ASC.Files.Thirdparty.Dropbox private Folder ToErrorFolder(ErrorFolder dropboxFolder) { if (dropboxFolder == null) return null; - var folder = ServiceProvider.GetService>(); - folder.ID = MakeId(dropboxFolder.ErrorId); - folder.ParentFolderID = null; - folder.CreateBy = DropboxProviderInfo.Owner; - folder.CreateOn = TenantUtil.DateTimeNow(); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = DropboxProviderInfo.Owner; - folder.ModifiedOn = TenantUtil.DateTimeNow(); - folder.ProviderId = DropboxProviderInfo.ID; - folder.ProviderKey = DropboxProviderInfo.ProviderKey; - folder.RootFolderCreator = DropboxProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = DropboxProviderInfo.RootFolderType; - folder.Shareable = false; + var folder = GetErrorFolder(new ErrorEntry(dropboxFolder.Error, dropboxFolder.ErrorId)); + folder.Title = MakeFolderTitle(dropboxFolder); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; - folder.Error = dropboxFolder.Error; return folder; } @@ -284,26 +174,15 @@ namespace ASC.Files.Thirdparty.Dropbox return ToErrorFile(dropboxFile as ErrorFile); } - var file = ServiceProvider.GetService>(); + var file = GetFile(); file.ID = MakeId(dropboxFile); - file.Access = FileShare.None; file.ContentLength = (long)dropboxFile.Size; - file.CreateBy = DropboxProviderInfo.Owner; file.CreateOn = TenantUtil.DateTimeFromUtc(dropboxFile.ServerModified); - file.FileStatus = FileStatus.None; file.FolderID = MakeId(GetParentFolderPath(dropboxFile)); - file.ModifiedBy = DropboxProviderInfo.Owner; file.ModifiedOn = TenantUtil.DateTimeFromUtc(dropboxFile.ServerModified); file.NativeAccessor = dropboxFile; - file.ProviderId = DropboxProviderInfo.ID; - file.ProviderKey = DropboxProviderInfo.ProviderKey; file.Title = MakeFileTitle(dropboxFile); - file.RootFolderId = MakeId(); - file.RootFolderType = DropboxProviderInfo.RootFolderType; - file.RootFolderCreator = DropboxProviderInfo.Owner; - file.Shared = false; - file.Version = 1; return file; } @@ -318,7 +197,7 @@ namespace ASC.Files.Thirdparty.Dropbox var dropboxFolderPath = MakeDropboxPath(folderId); try { - var folder = DropboxProviderInfo.GetDropboxFolder(dropboxFolderPath); + var folder = ProviderInfo.GetDropboxFolder(dropboxFolderPath); return folder; } catch (Exception ex) @@ -332,7 +211,7 @@ namespace ASC.Files.Thirdparty.Dropbox var dropboxFilePath = MakeDropboxPath(fileId); try { - var file = DropboxProviderInfo.GetDropboxFile(dropboxFilePath); + var file = ProviderInfo.GetDropboxFile(dropboxFilePath); return file; } catch (Exception ex) @@ -349,7 +228,7 @@ namespace ASC.Files.Thirdparty.Dropbox protected List GetDropboxItems(object parentId, bool? folder = null) { var dropboxFolderPath = MakeDropboxPath(parentId); - var items = DropboxProviderInfo.GetDropboxItems(dropboxFolderPath); + var items = ProviderInfo.GetDropboxItems(dropboxFolderPath); if (folder.HasValue) { diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 2c936d3669..9a7e9c9d33 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -42,29 +43,24 @@ using ASC.Web.Studio.Core; using Dropbox.Api.Files; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxFileDao : DropboxDaoBase, IFileDao { - public DropboxFileDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public DropboxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - } - + } + public void InvalidateCache(string fileId) { var dropboxFilePath = MakeDropboxPath(fileId); - DropboxProviderInfo.CacheReset(dropboxFilePath, true); + ProviderInfo.CacheReset(dropboxFilePath, true); var dropboxFile = GetDropboxFile(fileId); var parentPath = GetParentFolderPath(dropboxFile); - if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + if (parentPath != null) ProviderInfo.CacheReset(parentPath); } public File GetFile(string fileId) @@ -241,13 +237,13 @@ namespace ASC.Files.Thirdparty.Dropbox public Stream GetFileStream(File file, long offset) { var dropboxFilePath = MakeDropboxPath(file.ID); - DropboxProviderInfo.CacheReset(dropboxFilePath, true); + ProviderInfo.CacheReset(dropboxFilePath, true); var dropboxFile = GetDropboxFile(file.ID); if (dropboxFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); if (dropboxFile is ErrorFile) throw new Exception(((ErrorFile)dropboxFile).Error); - var fileStream = DropboxProviderInfo.Storage.DownloadStream(MakeDropboxPath(dropboxFile), (int)offset); + var fileStream = ProviderInfo.Storage.DownloadStream(MakeDropboxPath(dropboxFile), (int)offset); return fileStream; } @@ -272,24 +268,24 @@ namespace ASC.Files.Thirdparty.Dropbox if (file.ID != null) { var filePath = MakeDropboxPath(file.ID); - newDropboxFile = DropboxProviderInfo.Storage.SaveStream(filePath, fileStream); + newDropboxFile = ProviderInfo.Storage.SaveStream(filePath, fileStream); if (!newDropboxFile.Name.Equals(file.Title)) { var parentFolderPath = GetParentFolderPath(newDropboxFile); file.Title = GetAvailableTitle(file.Title, parentFolderPath, IsExist); - newDropboxFile = DropboxProviderInfo.Storage.MoveFile(filePath, parentFolderPath, file.Title); + newDropboxFile = ProviderInfo.Storage.MoveFile(filePath, parentFolderPath, file.Title); } } else if (file.FolderID != null) { var folderPath = MakeDropboxPath(file.FolderID); file.Title = GetAvailableTitle(file.Title, folderPath, IsExist); - newDropboxFile = DropboxProviderInfo.Storage.CreateFile(fileStream, file.Title, folderPath); + newDropboxFile = ProviderInfo.Storage.CreateFile(fileStream, file.Title, folderPath); } - DropboxProviderInfo.CacheReset(newDropboxFile); + ProviderInfo.CacheReset(newDropboxFile); var parentPath = GetParentFolderPath(newDropboxFile); - if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + if (parentPath != null) ProviderInfo.CacheReset(parentPath); return ToFile(newDropboxFile); } @@ -341,12 +337,12 @@ namespace ASC.Files.Thirdparty.Dropbox if (!(dropboxFile is ErrorFile)) { - DropboxProviderInfo.Storage.DeleteItem(dropboxFile); + ProviderInfo.Storage.DeleteItem(dropboxFile); } - DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); + ProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); var parentFolderPath = GetParentFolderPath(dropboxFile); - if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + if (parentFolderPath != null) ProviderInfo.CacheReset(parentFolderPath); } public bool IsExist(string title, object folderId) @@ -365,11 +361,11 @@ namespace ASC.Files.Thirdparty.Dropbox var fromFolderPath = GetParentFolderPath(dropboxFile); - dropboxFile = DropboxProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); + dropboxFile = ProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); - DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); - DropboxProviderInfo.CacheReset(fromFolderPath); - DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + ProviderInfo.CacheReset(MakeDropboxPath(dropboxFile), true); + ProviderInfo.CacheReset(fromFolderPath); + ProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); return MakeId(dropboxFile); } @@ -382,10 +378,10 @@ namespace ASC.Files.Thirdparty.Dropbox var toDropboxFolder = GetDropboxFolder(toFolderId); if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); - var newDropboxFile = DropboxProviderInfo.Storage.CopyFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); + var newDropboxFile = ProviderInfo.Storage.CopyFile(MakeDropboxPath(dropboxFile), MakeDropboxPath(toDropboxFolder), dropboxFile.Name); - DropboxProviderInfo.CacheReset(newDropboxFile); - DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + ProviderInfo.CacheReset(newDropboxFile); + ProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); return ToFile(newDropboxFile); } @@ -396,11 +392,11 @@ namespace ASC.Files.Thirdparty.Dropbox var parentFolderPath = GetParentFolderPath(dropboxFile); newTitle = GetAvailableTitle(newTitle, parentFolderPath, IsExist); - dropboxFile = DropboxProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), parentFolderPath, newTitle); + dropboxFile = ProviderInfo.Storage.MoveFile(MakeDropboxPath(dropboxFile), parentFolderPath, newTitle); - DropboxProviderInfo.CacheReset(dropboxFile); + ProviderInfo.CacheReset(dropboxFile); var parentPath = GetParentFolderPath(dropboxFile); - if (parentPath != null) DropboxProviderInfo.CacheReset(parentPath); + if (parentPath != null) ProviderInfo.CacheReset(parentPath); return MakeId(dropboxFile); } @@ -445,7 +441,7 @@ namespace ASC.Files.Thirdparty.Dropbox var uploadSession = new ChunkedUploadSession(file, contentLength); - var dropboxSession = DropboxProviderInfo.Storage.CreateResumableSession(); + var dropboxSession = ProviderInfo.Storage.CreateResumableSession(); if (dropboxSession != null) { uploadSession.Items["DropboxSession"] = dropboxSession; @@ -474,7 +470,7 @@ namespace ASC.Files.Thirdparty.Dropbox if (uploadSession.Items.ContainsKey("DropboxSession")) { var dropboxSession = uploadSession.GetItemOrDefault("DropboxSession"); - DropboxProviderInfo.Storage.Transfer(dropboxSession, uploadSession.BytesUploaded, stream); + ProviderInfo.Storage.Transfer(dropboxSession, uploadSession.BytesUploaded, stream); } else { @@ -508,17 +504,17 @@ namespace ASC.Files.Thirdparty.Dropbox if (file.ID != null) { var dropboxFilePath = MakeDropboxPath(file.ID); - dropboxFile = DropboxProviderInfo.Storage.FinishResumableSession(dropboxSession, dropboxFilePath, uploadSession.BytesUploaded); + dropboxFile = ProviderInfo.Storage.FinishResumableSession(dropboxSession, dropboxFilePath, uploadSession.BytesUploaded); } else { var folderPath = MakeDropboxPath(file.FolderID); var title = GetAvailableTitle(file.Title, folderPath, IsExist); - dropboxFile = DropboxProviderInfo.Storage.FinishResumableSession(dropboxSession, folderPath, title, uploadSession.BytesUploaded); + dropboxFile = ProviderInfo.Storage.FinishResumableSession(dropboxSession, folderPath, title, uploadSession.BytesUploaded); } - DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFile)); - DropboxProviderInfo.CacheReset(GetParentFolderPath(dropboxFile), false); + ProviderInfo.CacheReset(MakeDropboxPath(dropboxFile)); + ProviderInfo.CacheReset(GetParentFolderPath(dropboxFile), false); return ToFile(dropboxFile.AsFile); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs index 131e069b02..06910a71b5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -30,26 +30,24 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; - + +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxFolderDao : DropboxDaoBase, IFolderDao { - public DropboxFolderDao(IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public DropboxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - } + } public Folder GetFolder(string folderId) { @@ -180,11 +178,11 @@ namespace ASC.Files.Thirdparty.Dropbox folder.Title = GetAvailableTitle(folder.Title, dropboxFolderPath, IsExist); - var dropboxFolder = DropboxProviderInfo.Storage.CreateFolder(folder.Title, dropboxFolderPath); + var dropboxFolder = ProviderInfo.Storage.CreateFolder(folder.Title, dropboxFolderPath); - DropboxProviderInfo.CacheReset(dropboxFolder); + ProviderInfo.CacheReset(dropboxFolder); var parentFolderPath = GetParentFolderPath(dropboxFolder); - if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + if (parentFolderPath != null) ProviderInfo.CacheReset(parentFolderPath); return MakeId(dropboxFolder); } @@ -237,11 +235,11 @@ namespace ASC.Files.Thirdparty.Dropbox } if (!(dropboxFolder is ErrorFolder)) - DropboxProviderInfo.Storage.DeleteItem(dropboxFolder); + ProviderInfo.Storage.DeleteItem(dropboxFolder); - DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), true); + ProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), true); var parentFolderPath = GetParentFolderPath(dropboxFolder); - if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + if (parentFolderPath != null) ProviderInfo.CacheReset(parentFolderPath); } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) @@ -254,11 +252,11 @@ namespace ASC.Files.Thirdparty.Dropbox var fromFolderPath = GetParentFolderPath(dropboxFolder); - dropboxFolder = DropboxProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); + dropboxFolder = ProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); - DropboxProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), false); - DropboxProviderInfo.CacheReset(fromFolderPath); - DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + ProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), false); + ProviderInfo.CacheReset(fromFolderPath); + ProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); return MakeId(dropboxFolder); } @@ -271,11 +269,11 @@ namespace ASC.Files.Thirdparty.Dropbox var toDropboxFolder = GetDropboxFolder(toFolderId); if (toDropboxFolder is ErrorFolder) throw new Exception(((ErrorFolder)toDropboxFolder).Error); - var newDropboxFolder = DropboxProviderInfo.Storage.CopyFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); + var newDropboxFolder = ProviderInfo.Storage.CopyFolder(MakeDropboxPath(dropboxFolder), MakeDropboxPath(toDropboxFolder), dropboxFolder.Name); - DropboxProviderInfo.CacheReset(newDropboxFolder); - DropboxProviderInfo.CacheReset(MakeDropboxPath(newDropboxFolder), false); - DropboxProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); + ProviderInfo.CacheReset(newDropboxFolder); + ProviderInfo.CacheReset(MakeDropboxPath(newDropboxFolder), false); + ProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); return ToFolder(newDropboxFolder); } @@ -293,7 +291,7 @@ namespace ASC.Files.Thirdparty.Dropbox if (IsRoot(dropboxFolder)) { //It's root folder - DropboxDaoSelector.RenameProvider(DropboxProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else @@ -301,11 +299,11 @@ namespace ASC.Files.Thirdparty.Dropbox newTitle = GetAvailableTitle(newTitle, parentFolderPath, IsExist); //rename folder - dropboxFolder = DropboxProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), parentFolderPath, newTitle); + dropboxFolder = ProviderInfo.Storage.MoveFolder(MakeDropboxPath(dropboxFolder), parentFolderPath, newTitle); } - DropboxProviderInfo.CacheReset(dropboxFolder); - if (parentFolderPath != null) DropboxProviderInfo.CacheReset(parentFolderPath); + ProviderInfo.CacheReset(dropboxFolder); + if (parentFolderPath != null) ProviderInfo.CacheReset(parentFolderPath); return MakeId(dropboxFolder); } @@ -319,7 +317,7 @@ namespace ASC.Files.Thirdparty.Dropbox { var dropboxFolderPath = MakeDropboxPath(folderId); //note: without cache - return DropboxProviderInfo.Storage.GetItems(dropboxFolderPath).Count == 0; + return ProviderInfo.Storage.GetItems(dropboxFolderPath).Count == 0; } public bool UseTrashForRemove(Folder folder) @@ -339,7 +337,7 @@ namespace ASC.Files.Thirdparty.Dropbox public long GetMaxUploadSize(string folderId, bool chunkedUpload) { - var storageMaxUploadSize = DropboxProviderInfo.Storage.MaxChunkedUploadFileSize; + var storageMaxUploadSize = ProviderInfo.Storage.MaxChunkedUploadFileSize; return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index 60cafb10e7..a312b167ab 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -39,7 +39,7 @@ using Dropbox.Api.Files; namespace ASC.Files.Thirdparty.Dropbox { [DebuggerDisplay("{CustomerTitle}")] - internal class DropboxProviderInfo : IProviderInfo, IDisposable + internal class DropboxProviderInfo : IProviderInfo { public OAuth20Token Token { get; set; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs index 561be172a6..e1a4e2dd6b 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxSecurityDao.cs @@ -28,29 +28,26 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxSecurityDao : DropboxDaoBase, ISecurityDao { - public DropboxSecurityDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public DropboxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - } - + } + public void SetShare(FileShareRecord r) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs index 11b8446c63..cefea2f695 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxTagDao.cs @@ -30,19 +30,22 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxTagDao : DropboxDaoBase, ITagDao { - public DropboxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public DropboxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -70,7 +73,7 @@ namespace ASC.Files.Thirdparty.Dropbox public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = DropboxDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); var entryIDs = FilesDbContext.ThirdpartyIdMapping diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs index c586c03c9c..dfe38dc4fb 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs @@ -28,8 +28,8 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text.RegularExpressions; +using ASC.Common.Logging; using ASC.Common.Web; using ASC.Core; using ASC.Core.Common.EF; @@ -37,105 +37,24 @@ using ASC.Core.Tenants; using ASC.FederatedLogin.LoginProviders; using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Security; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using DriveFile = Google.Apis.Drive.v3.Data.File; namespace ASC.Files.Thirdparty.GoogleDrive { - internal abstract class GoogleDriveDaoBase : IThirdPartyProviderDao + internal abstract class GoogleDriveDaoBase : ThirdPartyProviderDao { - public RegexDaoSelectorBase GoogleDriveDaoSelector { get; set; } + public override string Id { get => "drive"; } - public int TenantID { get; set; } - public GoogleDriveProviderInfo GoogleDriveProviderInfo { get; set; } - public string PathPrefix { get; set; } - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - public TenantUtil TenantUtil { get; } - public FilesDbContext FilesDbContext { get; } - public SetupInfo SetupInfo { get; } - public FileUtility FileUtility { get; } - - public GoogleDriveDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo, - FileUtility fileUtility) + public GoogleDriveDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - TenantID = tenantManager.GetCurrentTenant().TenantId; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - SetupInfo = setupInfo; - FileUtility = fileUtility; } - public void Init(BaseProviderInfo googleDriveInfo, RegexDaoSelectorBase googleDriveDaoSelector) - { - GoogleDriveProviderInfo = googleDriveInfo.ProviderInfo; - PathPrefix = googleDriveInfo.PathPrefix; - GoogleDriveDaoSelector = googleDriveDaoSelector; - } - - public void Dispose() - { - if (GoogleDriveProviderInfo != null) - { - GoogleDriveProviderInfo.Dispose(); - } - } - - protected string MappingID(string id, bool saveIfNotExist = false) - { - if (id == null) return null; - - string result; - if (id.ToString().StartsWith("drive")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - - return result; - } - - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); - } - - protected static string MakeDriveId(object entryId) { var id = Convert.ToString(entryId, CultureInfo.InvariantCulture); @@ -162,18 +81,16 @@ namespace ASC.Files.Thirdparty.GoogleDrive return MakeId(path); } - protected string MakeId(string path = null) + protected override string MakeId(string path = null) { - return string.Format("{0}{1}", PathPrefix, - string.IsNullOrEmpty(path) || path == "root" || path == GoogleDriveProviderInfo.DriveRootId - ? "" : ("-|" + path.TrimStart('/'))); + return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "root" || path == ProviderInfo.DriveRootId ? "" : ("-|" + path.TrimStart('/'))); } protected string MakeFolderTitle(DriveFile driveFolder) { if (driveFolder == null || IsRoot(driveFolder)) { - return GoogleDriveProviderInfo.CustomerTitle; + return ProviderInfo.CustomerTitle; } return Global.ReplaceInvalidCharsAndTruncate(driveFolder.Name); @@ -183,7 +100,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive { if (driveFile == null || string.IsNullOrEmpty(driveFile.Name)) { - return GoogleDriveProviderInfo.ProviderKey; + return ProviderInfo.ProviderKey; } var title = driveFile.Name; @@ -217,25 +134,14 @@ namespace ASC.Files.Thirdparty.GoogleDrive var isRoot = IsRoot(driveEntry); - var folder = ServiceProvider.GetService>(); + var folder = GetFolder(); folder.ID = MakeId(driveEntry); folder.ParentFolderID = isRoot ? null : MakeId(GetParentDriveId(driveEntry)); - folder.CreateBy = GoogleDriveProviderInfo.Owner; - folder.CreateOn = isRoot ? GoogleDriveProviderInfo.CreateOn : (driveEntry.CreatedTime ?? default); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = GoogleDriveProviderInfo.Owner; - folder.ModifiedOn = isRoot ? GoogleDriveProviderInfo.CreateOn : (driveEntry.ModifiedTime ?? default); - folder.ProviderId = GoogleDriveProviderInfo.ID; - folder.ProviderKey = GoogleDriveProviderInfo.ProviderKey; - folder.RootFolderCreator = GoogleDriveProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + folder.CreateOn = isRoot ? ProviderInfo.CreateOn : (driveEntry.CreatedTime ?? default); + folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : (driveEntry.ModifiedTime ?? default); - folder.Shareable = false; folder.Title = MakeFolderTitle(driveEntry); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc) folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn); @@ -260,19 +166,9 @@ namespace ASC.Files.Thirdparty.GoogleDrive { if (driveEntry == null) return null; - var file = ServiceProvider.GetService>(); - file.ID = MakeId(driveEntry.ErrorId); - file.CreateBy = GoogleDriveProviderInfo.Owner; - file.CreateOn = TenantUtil.DateTimeNow(); - file.ModifiedBy = GoogleDriveProviderInfo.Owner; - file.ModifiedOn = TenantUtil.DateTimeNow(); - file.ProviderId = GoogleDriveProviderInfo.ID; - file.ProviderKey = GoogleDriveProviderInfo.ProviderKey; - file.RootFolderCreator = GoogleDriveProviderInfo.Owner; - file.RootFolderId = MakeId(); - file.RootFolderType = GoogleDriveProviderInfo.RootFolderType; + var file = GetErrorFile(new ErrorEntry(driveEntry.Error, driveEntry.ErrorId)); + file.Title = MakeFileTitle(driveEntry); - file.Error = driveEntry.Error; return file; } @@ -280,25 +176,10 @@ namespace ASC.Files.Thirdparty.GoogleDrive private Folder ToErrorFolder(ErrorDriveEntry driveEntry) { if (driveEntry == null) return null; - var folder = ServiceProvider.GetService>(); - folder.ID = MakeId(driveEntry.ErrorId); - folder.ParentFolderID = null; - folder.CreateBy = GoogleDriveProviderInfo.Owner; - folder.CreateOn = TenantUtil.DateTimeNow(); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = GoogleDriveProviderInfo.Owner; - folder.ModifiedOn = TenantUtil.DateTimeNow(); - folder.ProviderId = GoogleDriveProviderInfo.ID; - folder.ProviderKey = GoogleDriveProviderInfo.ProviderKey; - folder.RootFolderCreator = GoogleDriveProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = GoogleDriveProviderInfo.RootFolderType; - folder.Shareable = false; + var folder = GetErrorFolder(new ErrorEntry(driveEntry.Error, driveEntry.ErrorId)); + folder.Title = MakeFolderTitle(driveEntry); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; - folder.Error = driveEntry.Error; return folder; } @@ -313,26 +194,15 @@ namespace ASC.Files.Thirdparty.GoogleDrive return ToErrorFile(driveFile as ErrorDriveEntry); } - var file = ServiceProvider.GetService>(); + var file = GetFile(); file.ID = MakeId(driveFile.Id); - file.Access = FileShare.None; file.ContentLength = driveFile.Size.HasValue ? (long)driveFile.Size : 0; - file.CreateBy = GoogleDriveProviderInfo.Owner; - file.CreateOn = driveFile.CreatedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.CreatedTime.Value) : default(DateTime); - file.FileStatus = FileStatus.None; + file.CreateOn = driveFile.CreatedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.CreatedTime.Value) : default; file.FolderID = MakeId(GetParentDriveId(driveFile)); - file.ModifiedBy = GoogleDriveProviderInfo.Owner; - file.ModifiedOn = driveFile.ModifiedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.ModifiedTime.Value) : default(DateTime); + file.ModifiedOn = driveFile.ModifiedTime.HasValue ? TenantUtil.DateTimeFromUtc(driveFile.ModifiedTime.Value) : default; file.NativeAccessor = driveFile; - file.ProviderId = GoogleDriveProviderInfo.ID; - file.ProviderKey = GoogleDriveProviderInfo.ProviderKey; file.Title = MakeFileTitle(driveFile); - file.RootFolderId = MakeId(); - file.RootFolderType = GoogleDriveProviderInfo.RootFolderType; - file.RootFolderCreator = GoogleDriveProviderInfo.Owner; - file.Shared = false; - file.Version = 1; return file; } @@ -347,7 +217,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive var driveId = MakeDriveId(entryId); try { - var entry = GoogleDriveProviderInfo.GetDriveEntry(driveId); + var entry = ProviderInfo.GetDriveEntry(driveId); return entry; } catch (Exception ex) @@ -364,7 +234,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive protected List GetDriveEntries(object parentId, bool? folder = null) { var parentDriveId = MakeDriveId(parentId); - var entries = GoogleDriveProviderInfo.GetDriveEntries(parentDriveId, folder); + var entries = ProviderInfo.GetDriveEntries(parentDriveId, folder); return entries; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 6a8c00d123..672e625d7f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -40,24 +41,26 @@ using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + using DriveFile = Google.Apis.Drive.v3.Data.File; namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao { - public GoogleDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + public GoogleDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } public void InvalidateCache(string fileId) { var driveId = MakeDriveId(fileId); - GoogleDriveProviderInfo.CacheReset(driveId, true); + ProviderInfo.CacheReset(driveId, true); var driveFile = GetDriveEntry(fileId); var parentDriveId = GetParentDriveId(driveFile); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId); } public File GetFile(string fileId) @@ -231,12 +234,12 @@ namespace ASC.Files.Thirdparty.GoogleDrive public Stream GetFileStream(File file, long offset) { var driveId = MakeDriveId(file.ID); - GoogleDriveProviderInfo.CacheReset(driveId, true); + ProviderInfo.CacheReset(driveId, true); var driveFile = GetDriveEntry(file.ID); if (driveFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); if (driveFile is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)driveFile).Error); - var fileStream = GoogleDriveProviderInfo.Storage.DownloadStream(driveFile, (int)offset); + var fileStream = ProviderInfo.Storage.DownloadStream(driveFile, (int)offset); if (!driveFile.Size.HasValue && fileStream != null && fileStream.CanSeek) { @@ -265,16 +268,16 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (file.ID != null) { - newDriveFile = GoogleDriveProviderInfo.Storage.SaveStream(MakeDriveId(file.ID), fileStream, file.Title); + newDriveFile = ProviderInfo.Storage.SaveStream(MakeDriveId(file.ID), fileStream, file.Title); } else if (file.FolderID != null) { - newDriveFile = GoogleDriveProviderInfo.Storage.InsertEntry(fileStream, file.Title, MakeDriveId(file.FolderID)); + newDriveFile = ProviderInfo.Storage.InsertEntry(fileStream, file.Title, MakeDriveId(file.FolderID)); } - GoogleDriveProviderInfo.CacheReset(newDriveFile); + ProviderInfo.CacheReset(newDriveFile); var parentDriveId = GetParentDriveId(newDriveFile); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, false); return ToFile(newDriveFile); } @@ -326,12 +329,12 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (!(driveFile is ErrorDriveEntry)) { - GoogleDriveProviderInfo.Storage.DeleteEntry(driveFile.Id); + ProviderInfo.Storage.DeleteEntry(driveFile.Id); } - GoogleDriveProviderInfo.CacheReset(driveFile.Id); + ProviderInfo.CacheReset(driveFile.Id); var parentDriveId = GetParentDriveId(driveFile); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, false); } public bool IsExist(string title, object folderId) @@ -350,15 +353,15 @@ namespace ASC.Files.Thirdparty.GoogleDrive var fromFolderDriveId = GetParentDriveId(driveFile); - driveFile = GoogleDriveProviderInfo.Storage.InsertEntryIntoFolder(driveFile, toDriveFolder.Id); + driveFile = ProviderInfo.Storage.InsertEntryIntoFolder(driveFile, toDriveFolder.Id); if (fromFolderDriveId != null) { - GoogleDriveProviderInfo.Storage.RemoveEntryFromFolder(driveFile, fromFolderDriveId); + ProviderInfo.Storage.RemoveEntryFromFolder(driveFile, fromFolderDriveId); } - GoogleDriveProviderInfo.CacheReset(driveFile.Id); - GoogleDriveProviderInfo.CacheReset(fromFolderDriveId, false); - GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, false); + ProviderInfo.CacheReset(driveFile.Id); + ProviderInfo.CacheReset(fromFolderDriveId, false); + ProviderInfo.CacheReset(toDriveFolder.Id, false); return MakeId(driveFile.Id); } @@ -371,10 +374,10 @@ namespace ASC.Files.Thirdparty.GoogleDrive var toDriveFolder = GetDriveEntry(toFolderId); if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); - var newDriveFile = GoogleDriveProviderInfo.Storage.CopyEntry(toDriveFolder.Id, driveFile.Id); + var newDriveFile = ProviderInfo.Storage.CopyEntry(toDriveFolder.Id, driveFile.Id); - GoogleDriveProviderInfo.CacheReset(newDriveFile); - GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, false); + ProviderInfo.CacheReset(newDriveFile); + ProviderInfo.CacheReset(toDriveFolder.Id, false); return ToFile(newDriveFile); } @@ -384,11 +387,11 @@ namespace ASC.Files.Thirdparty.GoogleDrive var driveFile = GetDriveEntry(file.ID); driveFile.Name = newTitle; - driveFile = GoogleDriveProviderInfo.Storage.RenameEntry(driveFile.Id, driveFile.Name); + driveFile = ProviderInfo.Storage.RenameEntry(driveFile.Id, driveFile.Name); - GoogleDriveProviderInfo.CacheReset(driveFile); + ProviderInfo.CacheReset(driveFile); var parentDriveId = GetParentDriveId(driveFile); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, false); return MakeId(driveFile.Id); } @@ -441,10 +444,10 @@ namespace ASC.Files.Thirdparty.GoogleDrive else { var folder = GetDriveEntry(file.FolderID); - driveFile = GoogleDriveProviderInfo.Storage.FileConstructor(file.Title, null, folder.Id); + driveFile = ProviderInfo.Storage.FileConstructor(file.Title, null, folder.Id); } - var googleDriveSession = GoogleDriveProviderInfo.Storage.CreateResumableSession(driveFile, contentLength); + var googleDriveSession = ProviderInfo.Storage.CreateResumableSession(driveFile, contentLength); if (googleDriveSession != null) { uploadSession.Items["GoogleDriveSession"] = googleDriveSession; @@ -473,7 +476,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (uploadSession.Items.ContainsKey("GoogleDriveSession")) { var googleDriveSession = uploadSession.GetItemOrDefault("GoogleDriveSession"); - GoogleDriveProviderInfo.Storage.Transfer(googleDriveSession, stream, chunkLength); + ProviderInfo.Storage.Transfer(googleDriveSession, stream, chunkLength); } else { @@ -502,9 +505,9 @@ namespace ASC.Files.Thirdparty.GoogleDrive { var googleDriveSession = uploadSession.GetItemOrDefault("GoogleDriveSession"); - GoogleDriveProviderInfo.CacheReset(googleDriveSession.FileId); + ProviderInfo.CacheReset(googleDriveSession.FileId); var parentDriveId = googleDriveSession.FolderId; - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, false); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, false); return ToFile(GetDriveEntry(googleDriveSession.FileId)); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs index f7a5cb3b33..eb93407286 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -38,12 +39,13 @@ using ASC.Files.Core.EF; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveFolderDao : GoogleDriveDaoBase, IFolderDao { - public GoogleDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + public GoogleDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -170,11 +172,11 @@ namespace ASC.Files.Thirdparty.GoogleDrive { var driveFolderId = MakeDriveId(folder.ParentFolderID); - var driveFolder = GoogleDriveProviderInfo.Storage.InsertEntry(null, folder.Title, driveFolderId, true); + var driveFolder = ProviderInfo.Storage.InsertEntry(null, folder.Title, driveFolderId, true); - GoogleDriveProviderInfo.CacheReset(driveFolder); + ProviderInfo.CacheReset(driveFolder); var parentDriveId = GetParentDriveId(driveFolder); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, true); return MakeId(driveFolder); } @@ -221,11 +223,11 @@ namespace ASC.Files.Thirdparty.GoogleDrive } if (!(driveFolder is ErrorDriveEntry)) - GoogleDriveProviderInfo.Storage.DeleteEntry(driveFolder.Id); + ProviderInfo.Storage.DeleteEntry(driveFolder.Id); - GoogleDriveProviderInfo.CacheReset(driveFolder.Id); + ProviderInfo.CacheReset(driveFolder.Id); var parentDriveId = GetParentDriveId(driveFolder); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, true); } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) @@ -238,15 +240,15 @@ namespace ASC.Files.Thirdparty.GoogleDrive var fromFolderDriveId = GetParentDriveId(driveFolder); - driveFolder = GoogleDriveProviderInfo.Storage.InsertEntryIntoFolder(driveFolder, toDriveFolder.Id); + driveFolder = ProviderInfo.Storage.InsertEntryIntoFolder(driveFolder, toDriveFolder.Id); if (fromFolderDriveId != null) { - GoogleDriveProviderInfo.Storage.RemoveEntryFromFolder(driveFolder, fromFolderDriveId); + ProviderInfo.Storage.RemoveEntryFromFolder(driveFolder, fromFolderDriveId); } - GoogleDriveProviderInfo.CacheReset(driveFolder.Id); - GoogleDriveProviderInfo.CacheReset(fromFolderDriveId, true); - GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, true); + ProviderInfo.CacheReset(driveFolder.Id); + ProviderInfo.CacheReset(fromFolderDriveId, true); + ProviderInfo.CacheReset(toDriveFolder.Id, true); return MakeId(driveFolder.Id); } @@ -259,11 +261,11 @@ namespace ASC.Files.Thirdparty.GoogleDrive var toDriveFolder = GetDriveEntry(toFolderId); if (toDriveFolder is ErrorDriveEntry) throw new Exception(((ErrorDriveEntry)toDriveFolder).Error); - var newDriveFolder = GoogleDriveProviderInfo.Storage.InsertEntry(null, driveFolder.Name, toDriveFolder.Id, true); + var newDriveFolder = ProviderInfo.Storage.InsertEntry(null, driveFolder.Name, toDriveFolder.Id, true); - GoogleDriveProviderInfo.CacheReset(newDriveFolder); - GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id, true); - GoogleDriveProviderInfo.CacheReset(toDriveFolder.Id); + ProviderInfo.CacheReset(newDriveFolder); + ProviderInfo.CacheReset(toDriveFolder.Id, true); + ProviderInfo.CacheReset(toDriveFolder.Id); return ToFolder(newDriveFolder); } @@ -280,19 +282,19 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (IsRoot(driveFolder)) { //It's root folder - GoogleDriveDaoSelector.RenameProvider(GoogleDriveProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else { //rename folder driveFolder.Name = newTitle; - driveFolder = GoogleDriveProviderInfo.Storage.RenameEntry(driveFolder.Id, driveFolder.Name); + driveFolder = ProviderInfo.Storage.RenameEntry(driveFolder.Id, driveFolder.Name); } - GoogleDriveProviderInfo.CacheReset(driveFolder); + ProviderInfo.CacheReset(driveFolder); var parentDriveId = GetParentDriveId(driveFolder); - if (parentDriveId != null) GoogleDriveProviderInfo.CacheReset(parentDriveId, true); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, true); return MakeId(driveFolder.Id); } @@ -306,7 +308,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive { var driveId = MakeDriveId(folderId); //note: without cache - return GoogleDriveProviderInfo.Storage.GetEntries(driveId).Count == 0; + return ProviderInfo.Storage.GetEntries(driveId).Count == 0; } public bool UseTrashForRemove(Folder folder) @@ -326,7 +328,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive public long GetMaxUploadSize(string folderId, bool chunkedUpload) { - var storageMaxUploadSize = GoogleDriveProviderInfo.Storage.GetMaxUploadSize(); + var storageMaxUploadSize = ProviderInfo.Storage.GetMaxUploadSize(); return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index 629297e385..c85b4bb711 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -47,7 +47,7 @@ using DriveFile = Google.Apis.Drive.v3.Data.File; namespace ASC.Files.Thirdparty.GoogleDrive { [DebuggerDisplay("{CustomerTitle}")] - internal class GoogleDriveProviderInfo : IProviderInfo, IDisposable + internal class GoogleDriveProviderInfo : IProviderInfo { public OAuth20Token Token { get; set; } private string _driveRootId; diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs index f5e1d5db87..8a2c7a2ae9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveSecurityDao.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -37,11 +38,13 @@ using ASC.Files.Core.Security; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveSecurityDao : GoogleDriveDaoBase, ISecurityDao { - public GoogleDriveSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + public GoogleDriveSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs index 90ba9d40e2..8c6af5c06f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveTagDao.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -38,14 +39,16 @@ using ASC.Files.Thirdparty.Dropbox; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveTagDao : GoogleDriveDaoBase, ITagDao { - public GoogleDriveTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, FileUtility fileUtility) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, fileUtility) + public GoogleDriveTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } + #region ITagDao Members public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) @@ -70,7 +73,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = GoogleDriveDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); var entryIDs = FilesDbContext.ThirdpartyIdMapping diff --git a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs index 730abe9d93..94a02ad60f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/IDaoSelector.cs @@ -46,10 +46,10 @@ namespace ASC.Files.Thirdparty internal interface IDaoSelector where T : class, IProviderInfo { bool IsMatch(string id); - IFileDao GetFileDao(string id) where T1 : IFileDao, IThirdPartyProviderDao; - IFolderDao GetFolderDao(string id) where T1 : IFolderDao, IThirdPartyProviderDao; - ISecurityDao GetSecurityDao(string id) where T1 : ISecurityDao, IThirdPartyProviderDao; - ITagDao GetTagDao(string id) where T1 : ITagDao, IThirdPartyProviderDao; + IFileDao GetFileDao(string id) where T1 : ThirdPartyProviderDao, IFileDao; + IFolderDao GetFolderDao(string id) where T1 : ThirdPartyProviderDao, IFolderDao; + ISecurityDao GetSecurityDao(string id) where T1 : ThirdPartyProviderDao, ISecurityDao; + ITagDao GetTagDao(string id) where T1 : ThirdPartyProviderDao, ITagDao; string ConvertId(string id); string GetIdCode(string id); diff --git a/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs index 37912850cf..2bf93669b1 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -1,12 +1,191 @@ using System; +using System.Linq; +using System.Text.RegularExpressions; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Tenants; using ASC.Files.Core; +using ASC.Files.Core.EF; +using ASC.Files.Core.Security; using ASC.Files.Core.Thirdparty; +using ASC.Security.Cryptography; +using ASC.Web.Core.Files; +using ASC.Web.Studio.Core; + +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty { - internal interface IThirdPartyProviderDao : IDisposable where T : class, IProviderInfo + internal abstract class ThirdPartyProviderDao : IDisposable where T : class, IProviderInfo { - void Init(BaseProviderInfo t1, RegexDaoSelectorBase selectorBase); + public int TenantID { get; private set; } + public IServiceProvider ServiceProvider { get; } + public UserManager UserManager { get; } + public TenantUtil TenantUtil { get; } + public FilesDbContext FilesDbContext { get; } + public SetupInfo SetupInfo { get; } + public ILog Log { get; } + public FileUtility FileUtility { get; } + + public RegexDaoSelectorBase DaoSelector { get; set; } + public T ProviderInfo { get; set; } + public string PathPrefix { get; private set; } + + public abstract string Id { get; } + + public ThirdPartyProviderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility) + { + ServiceProvider = serviceProvider; + UserManager = userManager; + TenantUtil = tenantUtil; + FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); + SetupInfo = setupInfo; + Log = monitor.CurrentValue; + FileUtility = fileUtility; + TenantID = tenantManager.GetCurrentTenant().TenantId; + } + + public void Init(BaseProviderInfo providerInfo, RegexDaoSelectorBase selectorBase) + { + ProviderInfo = providerInfo.ProviderInfo; + PathPrefix = providerInfo.PathPrefix; + DaoSelector = selectorBase; + } + + protected IQueryable Query(DbSet set) where TSet : class, IDbFile + { + return set.Where(r => r.TenantId == TenantID); + } + + protected string MappingID(string id, bool saveIfNotExist = false) + { + if (id == null) return null; + + string result; + if (id.StartsWith(Id)) + { + result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); + } + else + { + result = FilesDbContext.ThirdpartyIdMapping + .Where(r => r.HashId == id) + .Select(r => r.Id) + .FirstOrDefault(); + } + if (saveIfNotExist) + { + var newMapping = new DbFilesThirdpartyIdMapping + { + Id = id, + HashId = result, + TenantId = TenantID + }; + + FilesDbContext.ThirdpartyIdMapping.Add(newMapping); + FilesDbContext.SaveChanges(); + } + return result; + } + + protected Folder GetFolder() + { + var folder = ServiceProvider.GetService>(); + + InitFileEntry(folder); + + folder.FolderType = FolderType.DEFAULT; + folder.Shareable = false; + folder.TotalFiles = 0; + folder.TotalSubFolders = 0; + + return folder; + } + + protected Folder GetErrorFolder(ErrorEntry entry) + { + var folder = GetFolder(); + + InitFileEntryError(folder, entry); + + folder.ParentFolderID = null; + + return folder; + } + + protected File GetFile() + { + var file = ServiceProvider.GetService>(); + + InitFileEntry(file); + + file.Access = FileShare.None; + file.FileStatus = FileStatus.None; + file.Shared = false; + file.Version = 1; + + return file; + } + + protected File GetErrorFile(ErrorEntry entry) + { + var file = GetFile(); + InitFileEntryError(file, entry); + return file; + } + + protected void InitFileEntry(FileEntry fileEntry) + { + fileEntry.CreateBy = ProviderInfo.Owner; + fileEntry.ModifiedBy = ProviderInfo.Owner; + fileEntry.ProviderId = ProviderInfo.ID; + fileEntry.ProviderKey = ProviderInfo.ProviderKey; + fileEntry.RootFolderCreator = ProviderInfo.Owner; + fileEntry.RootFolderType = ProviderInfo.RootFolderType; + fileEntry.RootFolderId = MakeId(); + } + + protected void InitFileEntryError(FileEntry fileEntry, ErrorEntry entry) + { + fileEntry.ID = MakeId(entry.ErrorId); + fileEntry.CreateOn = TenantUtil.DateTimeNow(); + fileEntry.ModifiedOn = TenantUtil.DateTimeNow(); + fileEntry.Error = entry.Error; + } + + protected abstract string MakeId(string path = null); + + public void Dispose() + { + if (ProviderInfo != null) + { + ProviderInfo.Dispose(); + } + } + } + + internal class ErrorEntry + { + public string Error { get; set; } + + public string ErrorId { get; set; } + + public ErrorEntry(string error, string errorId) + { + Error = error; + ErrorId = errorId; + } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs index 0743793bc7..e067ad1162 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -29,104 +29,30 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Security; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; +using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Microsoft.OneDrive.Sdk; namespace ASC.Files.Thirdparty.OneDrive { - internal abstract class OneDriveDaoBase : IThirdPartyProviderDao + internal abstract class OneDriveDaoBase : ThirdPartyProviderDao { - public RegexDaoSelectorBase OneDriveDaoSelector { get; set; } + public override string Id { get => "onedrive"; } - public int TenantID { get; private set; } - public OneDriveProviderInfo OneDriveProviderInfo { get; set; } - public string PathPrefix { get; set; } - public TenantUtil TenantUtil { get; } - public FilesDbContext FilesDbContext { get; } - public SetupInfo SetupInfo { get; } - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - - public OneDriveDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) + public OneDriveDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - TenantID = tenantManager.GetCurrentTenant().TenantId; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - SetupInfo = setupInfo; } - public void Init(BaseProviderInfo onedriveInfo, RegexDaoSelectorBase onedriveDaoSelector) - { - OneDriveProviderInfo = onedriveInfo.ProviderInfo; - PathPrefix = onedriveInfo.PathPrefix; - OneDriveDaoSelector = onedriveDaoSelector; - } - - public void Dispose() - { - if (OneDriveProviderInfo != null) - { - OneDriveProviderInfo.Dispose(); - } - } - - protected string MappingID(string id, bool saveIfNotExist = false) - { - if (id == null) return null; - - string result; - if (id.ToString().StartsWith("onedrive")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - return result; - } - - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); - } - - protected static string MakeOneDriveId(string entryId) { var id = entryId; @@ -155,7 +81,7 @@ namespace ASC.Files.Thirdparty.OneDrive return MakeId(id); } - protected string MakeId(string id = null) + protected override string MakeId(string id = null) { return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(id) || id == "" @@ -175,7 +101,7 @@ namespace ASC.Files.Thirdparty.OneDrive { if (onedriveItem == null || IsRoot(onedriveItem)) { - return OneDriveProviderInfo.CustomerTitle; + return ProviderInfo.CustomerTitle; } return Global.ReplaceInvalidCharsAndTruncate(onedriveItem.Name); @@ -194,25 +120,14 @@ namespace ASC.Files.Thirdparty.OneDrive var isRoot = IsRoot(onedriveFolder); - var folder = ServiceProvider.GetService>(); + var folder = GetFolder(); folder.ID = MakeId(isRoot ? string.Empty : onedriveFolder.Id); folder.ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(onedriveFolder)); - folder.CreateBy = OneDriveProviderInfo.Owner; - folder.CreateOn = isRoot ? OneDriveProviderInfo.CreateOn : (onedriveFolder.CreatedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.CreatedDateTime.Value.DateTime) : default(DateTime)); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = OneDriveProviderInfo.Owner; - folder.ModifiedOn = isRoot ? OneDriveProviderInfo.CreateOn : (onedriveFolder.LastModifiedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.LastModifiedDateTime.Value.DateTime) : default(DateTime)); - folder.ProviderId = OneDriveProviderInfo.ID; - folder.ProviderKey = OneDriveProviderInfo.ProviderKey; - folder.RootFolderCreator = OneDriveProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = OneDriveProviderInfo.RootFolderType; + folder.CreateOn = isRoot ? ProviderInfo.CreateOn : (onedriveFolder.CreatedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.CreatedDateTime.Value.DateTime) : default); + folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : (onedriveFolder.LastModifiedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFolder.LastModifiedDateTime.Value.DateTime) : default); - folder.Shareable = false; folder.Title = MakeItemTitle(onedriveFolder); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; return folder; } @@ -225,20 +140,10 @@ namespace ASC.Files.Thirdparty.OneDrive private File ToErrorFile(ErrorItem onedriveFile) { if (onedriveFile == null) return null; - var file = ServiceProvider.GetService>(); - file.ID = MakeId(onedriveFile.ErrorId); - file.CreateBy = OneDriveProviderInfo.Owner; - file.CreateOn = TenantUtil.DateTimeNow(); - file.ModifiedBy = OneDriveProviderInfo.Owner; - file.ModifiedOn = TenantUtil.DateTimeNow(); - file.ProviderId = OneDriveProviderInfo.ID; - file.ProviderKey = OneDriveProviderInfo.ProviderKey; - file.RootFolderCreator = OneDriveProviderInfo.Owner; - file.RootFolderId = MakeId(); - file.RootFolderType = OneDriveProviderInfo.RootFolderType; + var file = GetErrorFile(new ErrorEntry(onedriveFile.Error, onedriveFile.ErrorId)); + file.Title = MakeItemTitle(onedriveFile); - file.Error = onedriveFile.Error; return file; } @@ -247,25 +152,10 @@ namespace ASC.Files.Thirdparty.OneDrive { if (onedriveFolder == null) return null; - var folder = ServiceProvider.GetService>(); + var folder = GetErrorFolder(new ErrorEntry(onedriveFolder.Error, onedriveFolder.ErrorId)); - folder.ID = MakeId(onedriveFolder.ErrorId); - folder.ParentFolderID = null; - folder.CreateBy = OneDriveProviderInfo.Owner; - folder.CreateOn = TenantUtil.DateTimeNow(); - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = OneDriveProviderInfo.Owner; - folder.ModifiedOn = TenantUtil.DateTimeNow(); - folder.ProviderId = OneDriveProviderInfo.ID; - folder.ProviderKey = OneDriveProviderInfo.ProviderKey; - folder.RootFolderCreator = OneDriveProviderInfo.Owner; - folder.RootFolderId = MakeId(); - folder.RootFolderType = OneDriveProviderInfo.RootFolderType; - folder.Shareable = false; folder.Title = MakeItemTitle(onedriveFolder); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; - folder.Error = onedriveFolder.Error; + return folder; } @@ -284,23 +174,12 @@ namespace ASC.Files.Thirdparty.OneDrive var file = ServiceProvider.GetService>(); file.ID = MakeId(onedriveFile.Id); - file.Access = FileShare.None; file.ContentLength = onedriveFile.Size.HasValue ? (long)onedriveFile.Size : 0; - file.CreateBy = OneDriveProviderInfo.Owner; file.CreateOn = onedriveFile.CreatedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFile.CreatedDateTime.Value.DateTime) : default; - file.FileStatus = FileStatus.None; file.FolderID = MakeId(GetParentFolderId(onedriveFile)); - file.ModifiedBy = OneDriveProviderInfo.Owner; file.ModifiedOn = onedriveFile.LastModifiedDateTime.HasValue ? TenantUtil.DateTimeFromUtc(onedriveFile.LastModifiedDateTime.Value.DateTime) : default; file.NativeAccessor = onedriveFile; - file.ProviderId = OneDriveProviderInfo.ID; - file.ProviderKey = OneDriveProviderInfo.ProviderKey; file.Title = MakeItemTitle(onedriveFile); - file.RootFolderId = MakeId(); - file.RootFolderType = OneDriveProviderInfo.RootFolderType; - file.RootFolderCreator = OneDriveProviderInfo.Owner; - file.Shared = false; - file.Version = 1; return file; } @@ -315,7 +194,7 @@ namespace ASC.Files.Thirdparty.OneDrive var onedriveId = MakeOneDriveId(itemId); try { - return OneDriveProviderInfo.GetOneDriveItem(onedriveId); + return ProviderInfo.GetOneDriveItem(onedriveId); } catch (Exception ex) { @@ -331,7 +210,7 @@ namespace ASC.Files.Thirdparty.OneDrive protected List GetOneDriveItems(string parentId, bool? folder = null) { var onedriveFolderId = MakeOneDriveId(parentId); - var items = OneDriveProviderInfo.GetOneDriveItems(onedriveFolderId); + var items = ProviderInfo.GetOneDriveItems(onedriveFolderId); if (folder.HasValue) { diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index f690a91150..a740b3e915 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -40,31 +41,25 @@ using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; using Microsoft.OneDrive.Sdk; namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveFileDao : OneDriveDaoBase, IFileDao { - public OneDriveFileDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public OneDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } public void InvalidateCache(string fileId) { var onedriveFileId = MakeOneDriveId(fileId); - OneDriveProviderInfo.CacheReset(onedriveFileId); + ProviderInfo.CacheReset(onedriveFileId); var onedriveFile = GetOneDriveItem(fileId); var parentId = GetParentFolderId(onedriveFile); - if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + if (parentId != null) ProviderInfo.CacheReset(parentId); } public File GetFile(string fileId) @@ -238,13 +233,13 @@ namespace ASC.Files.Thirdparty.OneDrive public Stream GetFileStream(File file, long offset) { var onedriveFileId = MakeOneDriveId(file.ID); - OneDriveProviderInfo.CacheReset(onedriveFileId); + ProviderInfo.CacheReset(onedriveFileId); var onedriveFile = GetOneDriveItem(file.ID); if (onedriveFile == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound); if (onedriveFile is ErrorItem) throw new Exception(((ErrorItem)onedriveFile).Error); - var fileStream = OneDriveProviderInfo.Storage.DownloadStream(onedriveFile, (int)offset); + var fileStream = ProviderInfo.Storage.DownloadStream(onedriveFile, (int)offset); return fileStream; } @@ -268,11 +263,11 @@ namespace ASC.Files.Thirdparty.OneDrive if (file.ID != null) { - newOneDriveFile = OneDriveProviderInfo.Storage.SaveStream(MakeOneDriveId(file.ID), fileStream); + newOneDriveFile = ProviderInfo.Storage.SaveStream(MakeOneDriveId(file.ID), fileStream); if (!newOneDriveFile.Name.Equals(file.Title)) { file.Title = GetAvailableTitle(file.Title, GetParentFolderId(newOneDriveFile), IsExist); - newOneDriveFile = OneDriveProviderInfo.Storage.RenameItem(newOneDriveFile.Id, file.Title); + newOneDriveFile = ProviderInfo.Storage.RenameItem(newOneDriveFile.Id, file.Title); } } else if (file.FolderID != null) @@ -280,12 +275,12 @@ namespace ASC.Files.Thirdparty.OneDrive var folderId = MakeOneDriveId(file.FolderID); var folder = GetOneDriveItem(folderId); file.Title = GetAvailableTitle(file.Title, folderId, IsExist); - newOneDriveFile = OneDriveProviderInfo.Storage.CreateFile(fileStream, file.Title, MakeOneDrivePath(folder)); + newOneDriveFile = ProviderInfo.Storage.CreateFile(fileStream, file.Title, MakeOneDrivePath(folder)); } - if (newOneDriveFile != null) OneDriveProviderInfo.CacheReset(newOneDriveFile.Id); + if (newOneDriveFile != null) ProviderInfo.CacheReset(newOneDriveFile.Id); var parentId = GetParentFolderId(newOneDriveFile); - if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + if (parentId != null) ProviderInfo.CacheReset(parentId); return ToFile(newOneDriveFile); } @@ -336,11 +331,11 @@ namespace ASC.Files.Thirdparty.OneDrive } if (!(onedriveFile is ErrorItem)) - OneDriveProviderInfo.Storage.DeleteItem(onedriveFile); + ProviderInfo.Storage.DeleteItem(onedriveFile); - OneDriveProviderInfo.CacheReset(onedriveFile.Id); + ProviderInfo.CacheReset(onedriveFile.Id); var parentFolderId = GetParentFolderId(onedriveFile); - if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); } public bool IsExist(string title, object folderId) @@ -360,11 +355,11 @@ namespace ASC.Files.Thirdparty.OneDrive var fromFolderId = GetParentFolderId(onedriveFile); var newTitle = GetAvailableTitle(onedriveFile.Name, toOneDriveFolder.Id, IsExist); - onedriveFile = OneDriveProviderInfo.Storage.MoveItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); + onedriveFile = ProviderInfo.Storage.MoveItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); - OneDriveProviderInfo.CacheReset(onedriveFile.Id); - OneDriveProviderInfo.CacheReset(fromFolderId); - OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + ProviderInfo.CacheReset(onedriveFile.Id); + ProviderInfo.CacheReset(fromFolderId); + ProviderInfo.CacheReset(toOneDriveFolder.Id); return MakeId(onedriveFile.Id); } @@ -378,10 +373,10 @@ namespace ASC.Files.Thirdparty.OneDrive if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); var newTitle = GetAvailableTitle(onedriveFile.Name, toOneDriveFolder.Id, IsExist); - var newOneDriveFile = OneDriveProviderInfo.Storage.CopyItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); + var newOneDriveFile = ProviderInfo.Storage.CopyItem(onedriveFile.Id, newTitle, toOneDriveFolder.Id); - OneDriveProviderInfo.CacheReset(newOneDriveFile.Id); - OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + ProviderInfo.CacheReset(newOneDriveFile.Id); + ProviderInfo.CacheReset(toOneDriveFolder.Id); return ToFile(newOneDriveFile); } @@ -391,11 +386,11 @@ namespace ASC.Files.Thirdparty.OneDrive var onedriveFile = GetOneDriveItem(file.ID); newTitle = GetAvailableTitle(newTitle, GetParentFolderId(onedriveFile), IsExist); - onedriveFile = OneDriveProviderInfo.Storage.RenameItem(onedriveFile.Id, newTitle); + onedriveFile = ProviderInfo.Storage.RenameItem(onedriveFile.Id, newTitle); - OneDriveProviderInfo.CacheReset(onedriveFile.Id); + ProviderInfo.CacheReset(onedriveFile.Id); var parentId = GetParentFolderId(onedriveFile); - if (parentId != null) OneDriveProviderInfo.CacheReset(parentId); + if (parentId != null) ProviderInfo.CacheReset(parentId); return MakeId(onedriveFile.Id); } @@ -451,7 +446,7 @@ namespace ASC.Files.Thirdparty.OneDrive onedriveFile = new Item { Name = file.Title, ParentReference = new ItemReference { Id = folder.Id } }; } - var onedriveSession = OneDriveProviderInfo.Storage.CreateResumableSession(onedriveFile, contentLength); + var onedriveSession = ProviderInfo.Storage.CreateResumableSession(onedriveFile, contentLength); if (onedriveSession != null) { uploadSession.Items["OneDriveSession"] = onedriveSession; @@ -480,7 +475,7 @@ namespace ASC.Files.Thirdparty.OneDrive if (uploadSession.Items.ContainsKey("OneDriveSession")) { var oneDriveSession = uploadSession.GetItemOrDefault("OneDriveSession"); - OneDriveProviderInfo.Storage.Transfer(oneDriveSession, stream, chunkLength); + ProviderInfo.Storage.Transfer(oneDriveSession, stream, chunkLength); } else { @@ -509,9 +504,9 @@ namespace ASC.Files.Thirdparty.OneDrive { var oneDriveSession = uploadSession.GetItemOrDefault("OneDriveSession"); - OneDriveProviderInfo.CacheReset(oneDriveSession.FileId); + ProviderInfo.CacheReset(oneDriveSession.FileId); var parentDriveId = oneDriveSession.FolderId; - if (parentDriveId != null) OneDriveProviderInfo.CacheReset(parentDriveId); + if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId); return ToFile(GetOneDriveItem(oneDriveSession.FileId)); } @@ -530,7 +525,7 @@ namespace ASC.Files.Thirdparty.OneDrive if (oneDriveSession.Status != ResumableUploadSessionStatus.Completed) { - OneDriveProviderInfo.Storage.CancelTransfer(oneDriveSession); + ProviderInfo.Storage.CancelTransfer(oneDriveSession); oneDriveSession.Status = ResumableUploadSessionStatus.Aborted; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs index fade47f7a6..5d4b23f4fb 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs @@ -30,25 +30,22 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; - + +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveFolderDao : OneDriveDaoBase, IFolderDao { - public OneDriveFolderDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public OneDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -177,11 +174,11 @@ namespace ASC.Files.Thirdparty.OneDrive folder.Title = GetAvailableTitle(folder.Title, onedriveFolderId, IsExist); - var onedriveFolder = OneDriveProviderInfo.Storage.CreateFolder(folder.Title, onedriveFolderId); + var onedriveFolder = ProviderInfo.Storage.CreateFolder(folder.Title, onedriveFolderId); - OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + ProviderInfo.CacheReset(onedriveFolder.Id); var parentFolderId = GetParentFolderId(onedriveFolder); - if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); return MakeId(onedriveFolder); } @@ -234,11 +231,11 @@ namespace ASC.Files.Thirdparty.OneDrive } if (!(onedriveFolder is ErrorItem)) - OneDriveProviderInfo.Storage.DeleteItem(onedriveFolder); + ProviderInfo.Storage.DeleteItem(onedriveFolder); - OneDriveProviderInfo.CacheReset(onedriveFolder.Id); + ProviderInfo.CacheReset(onedriveFolder.Id); var parentFolderId = GetParentFolderId(onedriveFolder); - if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) @@ -252,11 +249,11 @@ namespace ASC.Files.Thirdparty.OneDrive var fromFolderId = GetParentFolderId(onedriveFolder); var newTitle = GetAvailableTitle(onedriveFolder.Name, toOneDriveFolder.Id, IsExist); - onedriveFolder = OneDriveProviderInfo.Storage.MoveItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); + onedriveFolder = ProviderInfo.Storage.MoveItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); - OneDriveProviderInfo.CacheReset(onedriveFolder.Id); - OneDriveProviderInfo.CacheReset(fromFolderId); - OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + ProviderInfo.CacheReset(onedriveFolder.Id); + ProviderInfo.CacheReset(fromFolderId); + ProviderInfo.CacheReset(toOneDriveFolder.Id); return MakeId(onedriveFolder.Id); } @@ -270,10 +267,10 @@ namespace ASC.Files.Thirdparty.OneDrive if (toOneDriveFolder is ErrorItem) throw new Exception(((ErrorItem)toOneDriveFolder).Error); var newTitle = GetAvailableTitle(onedriveFolder.Name, toOneDriveFolder.Id, IsExist); - var newOneDriveFolder = OneDriveProviderInfo.Storage.CopyItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); + var newOneDriveFolder = ProviderInfo.Storage.CopyItem(onedriveFolder.Id, newTitle, toOneDriveFolder.Id); - OneDriveProviderInfo.CacheReset(newOneDriveFolder.Id); - OneDriveProviderInfo.CacheReset(toOneDriveFolder.Id); + ProviderInfo.CacheReset(newOneDriveFolder.Id); + ProviderInfo.CacheReset(toOneDriveFolder.Id); return ToFolder(newOneDriveFolder); } @@ -291,7 +288,7 @@ namespace ASC.Files.Thirdparty.OneDrive if (IsRoot(onedriveFolder)) { //It's root folder - OneDriveDaoSelector.RenameProvider(OneDriveProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else @@ -299,11 +296,11 @@ namespace ASC.Files.Thirdparty.OneDrive newTitle = GetAvailableTitle(newTitle, parentFolderId, IsExist); //rename folder - onedriveFolder = OneDriveProviderInfo.Storage.RenameItem(onedriveFolder.Id, newTitle); + onedriveFolder = ProviderInfo.Storage.RenameItem(onedriveFolder.Id, newTitle); } - OneDriveProviderInfo.CacheReset(onedriveFolder.Id); - if (parentFolderId != null) OneDriveProviderInfo.CacheReset(parentFolderId); + ProviderInfo.CacheReset(onedriveFolder.Id); + if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); return MakeId(onedriveFolder.Id); } @@ -343,7 +340,7 @@ namespace ASC.Files.Thirdparty.OneDrive public long GetMaxUploadSize(string folderId, bool chunkedUpload) { - var storageMaxUploadSize = OneDriveProviderInfo.Storage.MaxChunkedUploadFileSize; + var storageMaxUploadSize = ProviderInfo.Storage.MaxChunkedUploadFileSize; return chunkedUpload ? storageMaxUploadSize : Math.Min(storageMaxUploadSize, SetupInfo.AvailableFileSize); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index 8120a2c4a4..dea82eb69c 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -43,7 +43,7 @@ using Microsoft.OneDrive.Sdk; namespace ASC.Files.Thirdparty.OneDrive { [DebuggerDisplay("{CustomerTitle}")] - internal class OneDriveProviderInfo : IProviderInfo, IDisposable + internal class OneDriveProviderInfo : IProviderInfo { public OAuth20Token Token { get; set; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs index 47c2865649..ee133e2056 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveSecurityDao.cs @@ -28,26 +28,23 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveSecurityDao : OneDriveDaoBase, ISecurityDao { - public OneDriveSecurityDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public OneDriveSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs index 5cc32b8ce8..e9c3f65cb8 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveTagDao.cs @@ -29,28 +29,26 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveTagDao : OneDriveDaoBase, ITagDao { - public OneDriveTagDao( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) - : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public OneDriveTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } + #region ITagDao Members public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) @@ -75,7 +73,7 @@ namespace ASC.Files.Thirdparty.OneDrive public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = OneDriveDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); var entryIDs = FilesDbContext.ThirdpartyIdMapping diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs index c8513e6d74..56b41aa494 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -44,7 +44,7 @@ namespace ASC.Files.Thirdparty protected internal abstract string Name { get; } protected internal abstract string Id { get; } - private Dictionary> Providers { get; set; } + private Dictionary> Providers { get; set; } protected RegexDaoSelectorBase( IServiceProvider serviceProvider, @@ -53,7 +53,7 @@ namespace ASC.Files.Thirdparty ServiceProvider = serviceProvider; DaoFactory = daoFactory; Selector = new Regex(@"^" + Id + @"-(?'id'\d+)(-(?'path'.*)){0,1}$", RegexOptions.Singleline | RegexOptions.Compiled); - Providers = new Dictionary>(); + Providers = new Dictionary>(); } public virtual string ConvertId(string id) @@ -93,27 +93,27 @@ namespace ASC.Files.Thirdparty return id != null && Selector.IsMatch(id); } - public virtual ISecurityDao GetSecurityDao(string id) where T1 : ISecurityDao, IThirdPartyProviderDao + public virtual ISecurityDao GetSecurityDao(string id) where T1 : ThirdPartyProviderDao, ISecurityDao { return GetDao(id); } - public virtual IFileDao GetFileDao(string id) where T1 : IFileDao, IThirdPartyProviderDao + public virtual IFileDao GetFileDao(string id) where T1 : ThirdPartyProviderDao, IFileDao { return GetDao(id); } - public virtual ITagDao GetTagDao(string id) where T1 : ITagDao, IThirdPartyProviderDao + public virtual ITagDao GetTagDao(string id) where T1 : ThirdPartyProviderDao, ITagDao { return GetDao(id); } - public virtual IFolderDao GetFolderDao(string id) where T1 : IFolderDao, IThirdPartyProviderDao + public virtual IFolderDao GetFolderDao(string id) where T1 : ThirdPartyProviderDao, IFolderDao { return GetDao(id); } - private T1 GetDao(string id) where T1 : IThirdPartyProviderDao + private T1 GetDao(string id) where T1 : ThirdPartyProviderDao { if (Providers.ContainsKey(id)) return (T1)Providers[id]; diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs index e321decdde..5f98516392 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointDaoBase.cs @@ -28,59 +28,26 @@ using System; using System.Linq; using System.Text.RegularExpressions; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; -using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; -using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; using Folder = Microsoft.SharePoint.Client.Folder; namespace ASC.Files.Thirdparty.SharePoint { - internal class SharePointDaoBase : IThirdPartyProviderDao + internal class SharePointDaoBase : ThirdPartyProviderDao { - public SharePointProviderInfo ProviderInfo { get; private set; } - public RegexDaoSelectorBase SharePointDaoSelector { get; private set; } + public override string Id { get => "spoint"; } - public SharePointDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo) + public SharePointDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - TenantID = tenantManager.GetCurrentTenant().TenantId; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - SetupInfo = setupInfo; - } - - public void Init(BaseProviderInfo sharePointInfo, RegexDaoSelectorBase sharePointDaoSelector) - { - ProviderInfo = sharePointInfo.ProviderInfo; - SharePointDaoSelector = sharePointDaoSelector; - } - - protected int TenantID { get; set; } - - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - public TenantUtil TenantUtil { get; } - public FilesDbContext FilesDbContext { get; } - public SetupInfo SetupInfo { get; } - - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); } protected string GetAvailableTitle(string requestTitle, Folder parentFolderID, Func isExist) @@ -114,39 +81,6 @@ namespace ASC.Files.Thirdparty.SharePoint return string.Format(" ({0}){1}", index + 1, staticText); } - protected string MappingID(string id, bool saveIfNotExist) - { - if (id == null) return null; - - string result; - - if (id.ToString().StartsWith("spoint")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - - return result; - } - protected void UpdatePathInDB(string oldValue, string newValue) { if (oldValue.Equals(newValue)) return; @@ -208,12 +142,9 @@ namespace ASC.Files.Thirdparty.SharePoint return MappingID(id, false); } - public void Dispose() + protected override string MakeId(string path = null) { - if (ProviderInfo != null) - { - ProviderInfo.Dispose(); - } + return path; } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 2d64429822..627f1b4e41 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; @@ -40,19 +41,16 @@ using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointFileDao : SharePointDaoBase, IFileDao { - public SharePointFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public SharePointFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } - public void Dispose() - { - ProviderInfo.Dispose(); - } - public void InvalidateCache(string fileId) { ProviderInfo.InvalidateStorage(); @@ -259,8 +257,8 @@ namespace ASC.Files.Thirdparty.SharePoint var folder = ProviderInfo.GetFolderById(file.FolderID); file.Title = GetAvailableTitle(file.Title, folder, IsExist); - var id = ProviderInfo.RenameFile(SharePointDaoSelector.ConvertId(resultFile.ID).ToString(), file.Title); - return GetFile(SharePointDaoSelector.ConvertId(id)); + var id = ProviderInfo.RenameFile(DaoSelector.ConvertId(resultFile.ID).ToString(), file.Title); + return GetFile(DaoSelector.ConvertId(id)); } return resultFile; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs index 1b80bf7465..5bb509e703 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs @@ -30,26 +30,25 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointFolderDao : SharePointDaoBase, IFolderDao { - public SharePointFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public SharePointFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } - public void Dispose() - { - ProviderInfo.Dispose(); - } - public Folder GetFolder(string folderId) { return ProviderInfo.ToFolder(ProviderInfo.GetFolderById(folderId)); @@ -260,7 +259,7 @@ namespace ASC.Files.Thirdparty.SharePoint if (ProviderInfo.SpRootFolderId.Equals(folder.ID)) { //It's root folder - SharePointDaoSelector.RenameProvider(ProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs index 233209e588..881575cfc3 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs @@ -48,7 +48,7 @@ using Folder = Microsoft.SharePoint.Client.Folder; namespace ASC.Files.Thirdparty.SharePoint { - public class SharePointProviderInfo : IProviderInfo, IDisposable + public class SharePointProviderInfo : IProviderInfo { private ClientContext clientContext; diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs index 3161bc1a38..898399f747 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointSecurityDao.cs @@ -28,19 +28,23 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointSecurityDao : SharePointDaoBase, ISecurityDao { - public SharePointSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public SharePointSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -85,11 +89,6 @@ namespace ASC.Files.Thirdparty.SharePoint { throw new NotImplementedException(); } - - public void Dispose() - { - ProviderInfo.Dispose(); - } } public static class SharePointSecurityDaoExtention diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs index 6d4e48dad2..8753d8ade6 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointTagDao.cs @@ -29,27 +29,26 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; +using Microsoft.Extensions.Options; + namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointTagDao : SharePointDaoBase, ITagDao { - public SharePointTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo) + public SharePointTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } - public void Dispose() - { - ProviderInfo.Dispose(); - } - public IEnumerable GetTags(TagType tagType, IEnumerable> fileEntries) { return new List(); @@ -73,7 +72,7 @@ namespace ASC.Files.Thirdparty.SharePoint public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = SharePointDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs index d077398713..044cd892ae 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxDaoBase.cs @@ -40,20 +40,22 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; -using ASC.Files.Core.Security; -using ASC.Files.Core.Thirdparty; -using ASC.Security.Cryptography; +using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Studio.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty.Sharpbox { - internal abstract class SharpBoxDaoBase : IThirdPartyProviderDao + internal abstract class SharpBoxDaoBase : ThirdPartyProviderDao { + public override string Id { get => "sbox"; } + + public SharpBoxDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + { + } + protected class ErrorEntry : ICloudDirectoryEntry { public ErrorEntry(Exception e, object id) @@ -149,66 +151,6 @@ namespace ASC.Files.Thirdparty.Sharpbox } } - public int TenantID { get; private set; } - - public SharpBoxDaoBase( - IServiceProvider serviceProvider, - UserManager userManager, - TenantManager tenantManager, - TenantUtil tenantUtil, - DbContextManager dbContextManager, - SetupInfo setupInfo, - IOptionsMonitor monitor) - { - TenantID = tenantManager.GetCurrentTenant().TenantId; - ServiceProvider = serviceProvider; - UserManager = userManager; - TenantUtil = tenantUtil; - FilesDbContext = dbContextManager.Get(FileConstant.DatabaseId); - SetupInfo = setupInfo; - Log = monitor.CurrentValue; - } - - public void Init(BaseProviderInfo sharpBoxInfo, RegexDaoSelectorBase sharpBoxDaoSelector) - { - SharpBoxProviderInfo = sharpBoxInfo.ProviderInfo; - PathPrefix = sharpBoxInfo.PathPrefix; - SharpBoxDaoSelector = sharpBoxDaoSelector; - } - - protected string MappingID(string id, bool saveIfNotExist) - { - if (id == null) return null; - - string result; - if (id.ToString().StartsWith("sbox")) - { - result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower(); - } - else - { - result = FilesDbContext.ThirdpartyIdMapping - .Where(r => r.HashId == id) - .Select(r => r.Id) - .FirstOrDefault(); - } - - if (saveIfNotExist) - { - var newMapping = new DbFilesThirdpartyIdMapping - { - Id = id, - HashId = result, - TenantId = TenantID - }; - - FilesDbContext.ThirdpartyIdMapping.Add(newMapping); - FilesDbContext.SaveChanges(); - } - - return result; - } - protected string MappingID(string id) { return MappingID(id, false); @@ -270,33 +212,16 @@ namespace ASC.Files.Thirdparty.Sharpbox } } - protected RegexDaoSelectorBase SharpBoxDaoSelector; - public SharpBoxProviderInfo SharpBoxProviderInfo { get; set; } - public string PathPrefix { get; private set; } - public IServiceProvider ServiceProvider { get; } - public UserManager UserManager { get; } - public TenantUtil TenantUtil { get; } - public FilesDbContext FilesDbContext { get; } - public SetupInfo SetupInfo { get; } - public ILog Log { get; } - - protected IQueryable Query(DbSet set) where T : class, IDbFile - { - return set.Where(r => r.TenantId == TenantID); - } - - protected string GetTenantColumnName(string table) - { - const string tenant = "tenant_id"; - if (!table.Contains(" ")) return tenant; - return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant; - } - protected string MakePath(object entryId) { return string.Format("/{0}", Convert.ToString(entryId, CultureInfo.InvariantCulture).Trim('/')); } + protected override string MakeId(string path = null) + { + return path; + } + protected string MakeId(ICloudFileSystemEntry entry) { var path = string.Empty; @@ -304,7 +229,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { try { - path = SharpBoxProviderInfo.Storage.GetFileSystemObjectPath(entry); + path = ProviderInfo.Storage.GetFileSystemObjectPath(entry); } catch (Exception ex) { @@ -323,7 +248,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { if (fsEntry is ICloudDirectoryEntry && IsRoot(fsEntry as ICloudDirectoryEntry)) { - return SharpBoxProviderInfo.CustomerTitle; + return ProviderInfo.CustomerTitle; } return Global.ReplaceInvalidCharsAndTruncate(fsEntry.Name); @@ -354,22 +279,15 @@ namespace ASC.Files.Thirdparty.Sharpbox //var childFoldersCount = fsEntry.OfType().Count();//NOTE: Removed due to performance isssues var isRoot = IsRoot(fsEntry); - var folder = ServiceProvider.GetService>(); + + var folder = GetFolder(); folder.ID = MakeId(fsEntry); folder.ParentFolderID = isRoot ? null : MakeId(fsEntry.Parent); - folder.CreateBy = SharpBoxProviderInfo.Owner; - folder.CreateOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified; - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = SharpBoxProviderInfo.Owner; - folder.ModifiedOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified; - folder.ProviderId = SharpBoxProviderInfo.ID; - folder.ProviderKey = SharpBoxProviderInfo.ProviderKey; - folder.RootFolderCreator = SharpBoxProviderInfo.Owner; + folder.CreateOn = isRoot ? ProviderInfo.CreateOn : fsEntry.Modified; + folder.ModifiedOn = isRoot ? ProviderInfo.CreateOn : fsEntry.Modified; folder.RootFolderId = MakeId(RootFolder()); - folder.RootFolderType = SharpBoxProviderInfo.RootFolderType; - folder.Shareable = false; folder.Title = MakeTitle(fsEntry); folder.TotalFiles = 0; /*fsEntry.Count - childFoldersCount NOTE: Removed due to performance isssues*/ folder.TotalSubFolders = 0; /*childFoldersCount NOTE: Removed due to performance isssues*/ @@ -394,20 +312,13 @@ namespace ASC.Files.Thirdparty.Sharpbox { if (fsEntry == null) return null; - var file = ServiceProvider.GetService>(); + var file = GetErrorFile(new Thirdparty.ErrorEntry(fsEntry.Error, null)); file.ID = MakeId(fsEntry); - file.CreateBy = SharpBoxProviderInfo.Owner; file.CreateOn = fsEntry.Modified; - file.ModifiedBy = SharpBoxProviderInfo.Owner; file.ModifiedOn = fsEntry.Modified; - file.ProviderId = SharpBoxProviderInfo.ID; - file.ProviderKey = SharpBoxProviderInfo.ProviderKey; - file.RootFolderCreator = SharpBoxProviderInfo.Owner; file.RootFolderId = MakeId(null); - file.RootFolderType = SharpBoxProviderInfo.RootFolderType; file.Title = MakeTitle(fsEntry); - file.Error = fsEntry.Error; return file; } @@ -415,25 +326,13 @@ namespace ASC.Files.Thirdparty.Sharpbox private Folder ToErrorFolder(ErrorEntry fsEntry) { if (fsEntry == null) return null; - var folder = ServiceProvider.GetService>(); + var folder = GetErrorFolder(new Thirdparty.ErrorEntry(fsEntry.Error, null)); folder.ID = MakeId(fsEntry); - folder.ParentFolderID = null; - folder.CreateBy = SharpBoxProviderInfo.Owner; folder.CreateOn = fsEntry.Modified; - folder.FolderType = FolderType.DEFAULT; - folder.ModifiedBy = SharpBoxProviderInfo.Owner; folder.ModifiedOn = fsEntry.Modified; - folder.ProviderId = SharpBoxProviderInfo.ID; - folder.ProviderKey = SharpBoxProviderInfo.ProviderKey; - folder.RootFolderCreator = SharpBoxProviderInfo.Owner; folder.RootFolderId = MakeId(null); - folder.RootFolderType = SharpBoxProviderInfo.RootFolderType; - folder.Shareable = false; folder.Title = MakeTitle(fsEntry); - folder.TotalFiles = 0; - folder.TotalSubFolders = 0; - folder.Error = fsEntry.Error; return folder; } @@ -448,34 +347,23 @@ namespace ASC.Files.Thirdparty.Sharpbox return ToErrorFile(fsEntry as ErrorEntry); } - var file = ServiceProvider.GetService>(); - + var file = GetFile(); file.ID = MakeId(fsEntry); - file.Access = FileShare.None; file.ContentLength = fsEntry.Length; - file.CreateBy = SharpBoxProviderInfo.Owner; file.CreateOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified; - file.FileStatus = FileStatus.None; file.FolderID = MakeId(fsEntry.Parent); - file.ModifiedBy = SharpBoxProviderInfo.Owner; file.ModifiedOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified; file.NativeAccessor = fsEntry; - file.ProviderId = SharpBoxProviderInfo.ID; - file.ProviderKey = SharpBoxProviderInfo.ProviderKey; file.Title = MakeTitle(fsEntry); file.RootFolderId = MakeId(RootFolder()); - file.RootFolderType = SharpBoxProviderInfo.RootFolderType; - file.RootFolderCreator = SharpBoxProviderInfo.Owner; - file.Shared = false; - file.Version = 1; return file; } protected ICloudDirectoryEntry RootFolder() { - return SharpBoxProviderInfo.Storage.GetRoot(); + return ProviderInfo.Storage.GetRoot(); } protected ICloudDirectoryEntry GetFolderById(object folderId) @@ -485,7 +373,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var path = MakePath(folderId); return path == "/" ? RootFolder() - : SharpBoxProviderInfo.Storage.GetFolder(path); + : ProviderInfo.Storage.GetFolder(path); } catch (SharpBoxException sharpBoxException) { @@ -505,7 +393,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { try { - return SharpBoxProviderInfo.Storage.GetFile(MakePath(fileId), null); + return ProviderInfo.Storage.GetFile(MakePath(fileId), null); } catch (SharpBoxException sharpBoxException) { @@ -523,12 +411,12 @@ namespace ASC.Files.Thirdparty.Sharpbox protected IEnumerable GetFolderFiles(object folderId) { - return GetFolderFiles(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId))); + return GetFolderFiles(ProviderInfo.Storage.GetFolder(MakePath(folderId))); } protected IEnumerable GetFolderSubfolders(object folderId) { - return GetFolderSubfolders(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId))); + return GetFolderSubfolders(ProviderInfo.Storage.GetFolder(MakePath(folderId))); } protected IEnumerable GetFolderFiles(ICloudDirectoryEntry folder) @@ -571,13 +459,5 @@ namespace ASC.Files.Thirdparty.Sharpbox var staticText = match.Value.Substring(string.Format(" ({0})", index).Length); return string.Format(" ({0}){1}", index + 1, staticText); } - - public void Dispose() - { - if (SharpBoxProviderInfo != null) - { - SharpBoxProviderInfo.Dispose(); - } - } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 05e21b4817..25eb8e4808 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -52,13 +52,13 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao { - public SharpBoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + public SharpBoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } public void InvalidateCache(string fileId) { - SharpBoxProviderInfo.InvalidateStorage(); + ProviderInfo.InvalidateStorage(); } public File GetFile(string fileId) @@ -278,13 +278,13 @@ namespace ASC.Files.Thirdparty.Sharpbox ICloudFileSystemEntry entry = null; if (file.ID != null) { - entry = SharpBoxProviderInfo.Storage.GetFile(MakePath(file.ID), null); + entry = ProviderInfo.Storage.GetFile(MakePath(file.ID), null); } else if (file.FolderID != null) { var folder = GetFolderById(file.FolderID); file.Title = GetAvailableTitle(file.Title, folder, IsExist); - entry = SharpBoxProviderInfo.Storage.CreateFile(folder, file.Title); + entry = ProviderInfo.Storage.CreateFile(folder, file.Title); } if (entry == null) @@ -316,7 +316,7 @@ namespace ASC.Files.Thirdparty.Sharpbox if (file.ID != null && !entry.Name.Equals(file.Title)) { file.Title = GetAvailableTitle(file.Title, entry.Parent, IsExist); - SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, file.Title); + ProviderInfo.Storage.RenameFileSystemEntry(entry, file.Title); } return ToFile(entry); @@ -368,12 +368,12 @@ namespace ASC.Files.Thirdparty.Sharpbox } if (!(file is ErrorEntry)) - SharpBoxProviderInfo.Storage.DeleteFileSystemEntry(file); + ProviderInfo.Storage.DeleteFileSystemEntry(file); } public bool IsExist(string title, object folderId) { - var folder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId)); + var folder = ProviderInfo.Storage.GetFolder(MakePath(folderId)); return IsExist(title, folder); } @@ -381,7 +381,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { try { - return SharpBoxProviderInfo.Storage.GetFileSystemObject(title, folder) != null; + return ProviderInfo.Storage.GetFileSystemObject(title, folder) != null; } catch (ArgumentException) { @@ -400,7 +400,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var oldFileId = MakeId(entry); - if (!SharpBoxProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) + if (!ProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) throw new Exception("Error while moving"); var newFileId = MakeId(entry); @@ -413,7 +413,7 @@ namespace ASC.Files.Thirdparty.Sharpbox public File CopyFile(string fileId, string toFolderId) { var file = GetFileById(fileId); - if (!SharpBoxProviderInfo.Storage.CopyFileSystemEntry(MakePath(fileId), MakePath(toFolderId))) + if (!ProviderInfo.Storage.CopyFileSystemEntry(MakePath(fileId), MakePath(toFolderId))) throw new Exception("Error while copying"); return ToFile(GetFolderById(toFolderId).FirstOrDefault(x => x.Name == file.Name)); } @@ -431,7 +431,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var folder = GetFolderById(file.FolderID); newTitle = GetAvailableTitle(newTitle, folder, IsExist); - if (SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) + if (ProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) { //File data must be already updated by provider //We can't search google files by title because root can have multiple folders with the same name @@ -481,7 +481,7 @@ namespace ASC.Files.Thirdparty.Sharpbox else { var folder = GetFolderById(file.FolderID); - sharpboxFile = SharpBoxProviderInfo.Storage.CreateFile(folder, GetAvailableTitle(file.Title, folder, IsExist)); + sharpboxFile = ProviderInfo.Storage.CreateFile(folder, GetAvailableTitle(file.Title, folder, IsExist)); isNewFile = true; } @@ -520,7 +520,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var isNewFile = uploadSession.Items.ContainsKey("IsNewFile") && uploadSession.GetItemOrDefault("IsNewFile"); var sharpboxFile = isNewFile - ? SharpBoxProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) + ? ProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) : GetFileById(sharpboxSession.FileId); sharpboxFile.GetDataTransferAccessor().Transfer(sharpboxSession, stream, chunkLength); @@ -571,7 +571,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var isNewFile = uploadSession.Items.ContainsKey("IsNewFile") && uploadSession.GetItemOrDefault("IsNewFile"); var sharpboxFile = isNewFile - ? SharpBoxProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) + ? ProviderInfo.Storage.CreateFile(GetFolderById(sharpboxSession.ParentId), sharpboxSession.FileName) : GetFileById(sharpboxSession.FileId); sharpboxFile.GetDataTransferAccessor().AbortResumableSession(sharpboxSession); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs index 0365b370e5..205721380d 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs @@ -42,6 +42,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Resources; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; using Microsoft.Extensions.Options; @@ -50,7 +51,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxFolderDao : SharpBoxDaoBase, IFolderDao { - public SharpBoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + public SharpBoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -61,7 +62,7 @@ namespace ASC.Files.Thirdparty.Sharpbox public Folder GetFolder(string title, string parentId) { - var parentFolder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(parentId)); + var parentFolder = ProviderInfo.Storage.GetFolder(MakePath(parentId)); return ToFolder(parentFolder.OfType().FirstOrDefault(x => x.Name.Equals(title, StringComparison.OrdinalIgnoreCase))); } @@ -77,7 +78,7 @@ namespace ASC.Files.Thirdparty.Sharpbox public List> GetFolders(string parentId) { - var parentFolder = SharpBoxProviderInfo.Storage.GetFolder(MakePath(parentId)); + var parentFolder = ProviderInfo.Storage.GetFolder(MakePath(parentId)); return parentFolder.OfType().Select(ToFolder).ToList(); } @@ -171,7 +172,7 @@ namespace ASC.Files.Thirdparty.Sharpbox if (folder.ID != null) { //Create with id - var savedfolder = SharpBoxProviderInfo.Storage.CreateFolder(MakePath(folder.ID)); + var savedfolder = ProviderInfo.Storage.CreateFolder(MakePath(folder.ID)); return MakeId(savedfolder); } if (folder.ParentFolderID != null) @@ -180,7 +181,7 @@ namespace ASC.Files.Thirdparty.Sharpbox folder.Title = GetAvailableTitle(folder.Title, parentFolder, IsExist); - var newFolder = SharpBoxProviderInfo.Storage.CreateFolder(folder.Title, parentFolder); + var newFolder = ProviderInfo.Storage.CreateFolder(folder.Title, parentFolder); return MakeId(newFolder); } } @@ -243,14 +244,14 @@ namespace ASC.Files.Thirdparty.Sharpbox } if (!(folder is ErrorEntry)) - SharpBoxProviderInfo.Storage.DeleteFileSystemEntry(folder); + ProviderInfo.Storage.DeleteFileSystemEntry(folder); } public bool IsExist(string title, ICloudDirectoryEntry folder) { try { - return SharpBoxProviderInfo.Storage.GetFileSystemObject(title, folder) != null; + return ProviderInfo.Storage.GetFileSystemObject(title, folder) != null; } catch (ArgumentException) { @@ -270,7 +271,7 @@ namespace ASC.Files.Thirdparty.Sharpbox var oldFolderId = MakeId(entry); - if (!SharpBoxProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) + if (!ProviderInfo.Storage.MoveFileSystemEntry(entry, folder)) throw new Exception("Error while moving"); var newFolderId = MakeId(entry); @@ -283,7 +284,7 @@ namespace ASC.Files.Thirdparty.Sharpbox public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var folder = GetFolderById(folderId); - if (!SharpBoxProviderInfo.Storage.CopyFileSystemEntry(MakePath(folderId), MakePath(toFolderId))) + if (!ProviderInfo.Storage.CopyFileSystemEntry(MakePath(folderId), MakePath(toFolderId))) throw new Exception("Error while copying"); return ToFolder(GetFolderById(toFolderId).OfType().FirstOrDefault(x => x.Name == folder.Name)); } @@ -303,7 +304,7 @@ namespace ASC.Files.Thirdparty.Sharpbox if ("/".Equals(MakePath(folder.ID))) { //It's root folder - SharpBoxDaoSelector.RenameProvider(SharpBoxProviderInfo, newTitle); + DaoSelector.RenameProvider(ProviderInfo, newTitle); //rename provider customer title } else @@ -312,7 +313,7 @@ namespace ASC.Files.Thirdparty.Sharpbox newTitle = GetAvailableTitle(newTitle, parentFolder, IsExist); //rename folder - if (SharpBoxProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) + if (ProviderInfo.Storage.RenameFileSystemEntry(entry, newTitle)) { //Folder data must be already updated by provider //We can't search google folders by title because root can have multiple folders with the same name @@ -355,8 +356,8 @@ namespace ASC.Files.Thirdparty.Sharpbox { var storageMaxUploadSize = chunkedUpload - ? SharpBoxProviderInfo.Storage.CurrentConfiguration.Limits.MaxChunkedUploadFileSize - : SharpBoxProviderInfo.Storage.CurrentConfiguration.Limits.MaxUploadFileSize; + ? ProviderInfo.Storage.CurrentConfiguration.Limits.MaxChunkedUploadFileSize + : ProviderInfo.Storage.CurrentConfiguration.Limits.MaxUploadFileSize; if (storageMaxUploadSize == -1) storageMaxUploadSize = long.MaxValue; diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs index 03e70257db..c98d8b7d5f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -38,7 +38,7 @@ using Microsoft.Extensions.Options; namespace ASC.Files.Thirdparty.Sharpbox { - internal class SharpBoxProviderInfo : IProviderInfo, IDisposable + internal class SharpBoxProviderInfo : IProviderInfo { public int ID { get; set; } public Guid Owner { get; set; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs index 3f75077106..1b67f5163f 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxSecurityDao.cs @@ -35,6 +35,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Core.Security; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; using Microsoft.Extensions.Options; @@ -43,7 +44,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxSecurityDao : SharpBoxDaoBase, ISecurityDao { - public SharpBoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + public SharpBoxSecurityDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs index 4b4b1fb365..7645a48431 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxTagDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; using ASC.Files.Thirdparty.Dropbox; +using ASC.Web.Core.Files; using ASC.Web.Studio.Core; using Microsoft.Extensions.Options; @@ -44,7 +45,7 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxTagDao : SharpBoxDaoBase, ITagDao { - public SharpBoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor) + public SharpBoxTagDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } @@ -72,7 +73,7 @@ namespace ASC.Files.Thirdparty.Sharpbox public IEnumerable GetNewTags(Guid subject, Folder parentFolder, bool deepSearch) { - var folderId = SharpBoxDaoSelector.ConvertId(parentFolder.ID); + var folderId = DaoSelector.ConvertId(parentFolder.ID); var fakeFolderId = parentFolder.ID.ToString(); From 98eb263efd985607bb718a58e03cceb63af7a2fc Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 17 Mar 2020 17:47:39 +0300 Subject: [PATCH 18/30] Files: thirdparty. Fix --- .../ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs | 5 ++++- .../Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs | 5 ++++- .../Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs index bfb6912075..ef23278eb2 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -203,7 +203,10 @@ namespace ASC.Files.Thirdparty.Box public void Dispose() { - Storage.Close(); + if (Storage != null) + { + Storage.Close(); + } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index dea82eb69c..9e704bd508 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -179,7 +179,10 @@ namespace ASC.Files.Thirdparty.OneDrive public void Dispose() { - Storage.Close(); + if (Storage != null && Storage.IsOpened) + { + Storage.Close(); + } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs index c98d8b7d5f..de89024cde 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -169,8 +169,10 @@ namespace ASC.Files.Thirdparty.Sharpbox public void Dispose() { - if (Storage.IsOpened) + if (Storage != null && Storage.IsOpened) + { Storage.Close(); + } } } From 4a543560a7079da67332e346332bdfe3e583f418 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 18 Mar 2020 16:19:37 +0300 Subject: [PATCH 19/30] Files: api --- .../Server/Controllers/FilesController.cs | 621 +++++----- .../Server/Helpers/FilesControllerHelper.cs | 1019 +++++++++++++++++ products/ASC.Files/Server/Model/BatchModel.cs | 16 +- 3 files changed, 1324 insertions(+), 332 deletions(-) create mode 100644 products/ASC.Files/Server/Helpers/FilesControllerHelper.cs diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index c7152a576c..ec0c81d792 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -29,22 +29,19 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Net; using System.Runtime.Serialization; -using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; -using System.Web; using ASC.Api.Core; -using ASC.Api.Utils; using ASC.Common; -using ASC.Common.Web; using ASC.Core; using ASC.Core.Common.Configuration; using ASC.Core.Users; using ASC.FederatedLogin.Helpers; using ASC.FederatedLogin.LoginProviders; using ASC.Files.Core; +using ASC.Files.Helpers; using ASC.Files.Model; using ASC.MessagingSystem; using ASC.Web.Api.Routing; @@ -61,11 +58,11 @@ using ASC.Web.Studio.Utility; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ActionConstraints; using Newtonsoft.Json.Linq; using FileShare = ASC.Files.Core.Security.FileShare; -using MimeMapping = ASC.Common.Web.MimeMapping; using SortedByType = ASC.Files.Core.SortedByType; namespace ASC.Api.Documents @@ -80,6 +77,8 @@ namespace ASC.Api.Documents private readonly ApiContext ApiContext; private readonly FileStorageService FileStorageService; + public FilesControllerHelper FilesControllerHelperString { get; } + public FilesControllerHelper FilesControllerHelperInt { get; } public FileStorageService FileStorageServiceInt { get; } public GlobalFolderHelper GlobalFolderHelper { get; } public FileWrapperHelper FileWrapperHelper { get; } @@ -119,6 +118,8 @@ namespace ASC.Api.Documents /// public FilesController( ApiContext context, + FilesControllerHelper filesControllerHelperString, + FilesControllerHelper filesControllerHelperInt, FileStorageService fileStorageService, FileStorageService fileStorageServiceInt, GlobalFolderHelper globalFolderHelper, @@ -150,6 +151,8 @@ namespace ASC.Api.Documents ProductEntryPoint productEntryPoint) { ApiContext = context; + FilesControllerHelperString = filesControllerHelperString; + FilesControllerHelperInt = filesControllerHelperInt; FileStorageService = fileStorageService; FileStorageServiceInt = fileStorageServiceInt; GlobalFolderHelper = globalFolderHelper; @@ -258,9 +261,9 @@ namespace ASC.Api.Documents /// Folders /// Trash folder contents [Read("@trash")] - public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(GlobalFolderHelper.GetFolderTrash(), userIdOrGroupId, filterType); + return ToFolderContentWrapper(Convert.ToInt32(GlobalFolderHelper.FolderTrash), userIdOrGroupId, filterType); } /// @@ -277,13 +280,13 @@ namespace ASC.Api.Documents [Read("{folderId}", order: int.MaxValue)] public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); + return FilesControllerHelperString.GetFolder(folderId, userIdOrGroupId, filterType); } [Read("{folderId:int}", order: int.MaxValue)] public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType) { - return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); + return FilesControllerHelperInt.GetFolder(folderId, userIdOrGroupId, filterType); } /// @@ -305,10 +308,10 @@ namespace ASC.Api.Documents /// List of files when posted as multipart/form-data /// Uploaded file [Create("@my/upload")] - public object UploadFileToMy(UploadModel uploadModel) + public List> UploadFileToMy(UploadModel uploadModel) { uploadModel.CreateNewIfExist = false; - return UploadFile(GlobalFolderHelper.FolderMy.ToString(), uploadModel); + return UploadFile(GlobalFolderHelper.FolderMy, uploadModel); } /// @@ -330,10 +333,10 @@ namespace ASC.Api.Documents /// List of files when posted as multipart/form-data /// Uploaded file [Create("@common/upload")] - public object UploadFileToCommon(UploadModel uploadModel) + public List> UploadFileToCommon(UploadModel uploadModel) { uploadModel.CreateNewIfExist = false; - return UploadFile(GlobalFolderHelper.FolderCommon.ToString(), uploadModel); + return UploadFile(GlobalFolderHelper.FolderCommon, uploadModel); } @@ -360,35 +363,15 @@ namespace ASC.Api.Documents /// Keep status conversation after finishing /// Uploaded file [Create("{folderId}/upload")] - public object UploadFile(string folderId, UploadModel uploadModel) + public List> UploadFile(string folderId, UploadModel uploadModel) { - if (uploadModel.StoreOriginalFileFlag.HasValue) - { - FilesSettingsHelper.StoreOriginalFiles = uploadModel.StoreOriginalFileFlag.Value; - } + return FilesControllerHelperString.UploadFile(folderId, uploadModel); + } - if (uploadModel.Files != null && uploadModel.Files.Any()) - { - if (uploadModel.Files.Count() == 1) - { - //Only one file. return it - var postedFile = uploadModel.Files.First(); - return InsertFile(folderId, postedFile.OpenReadStream(), postedFile.FileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus); - } - //For case with multiple files - return uploadModel.Files.Select(postedFile => InsertFile(folderId, postedFile.OpenReadStream(), postedFile.FileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus)).ToList(); - } - if (uploadModel.File != null) - { - var fileName = "file" + MimeMapping.GetExtention(uploadModel.ContentType.MediaType); - if (uploadModel.ContentDisposition != null) - { - fileName = uploadModel.ContentDisposition.FileName; - } - - return InsertFile(folderId, uploadModel.File, fileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus); - } - throw new InvalidOperationException("No input files"); + [Create("{folderId:int}/upload")] + public List> UploadFile(int folderId, UploadModel uploadModel) + { + return FilesControllerHelperInt.UploadFile(folderId, uploadModel); } /// @@ -401,9 +384,9 @@ namespace ASC.Api.Documents /// Uploads /// [Create("@my/insert")] - public FileWrapper InsertFileToMy(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + public FileWrapper InsertFileToMy(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { - return InsertFile(GlobalFolderHelper.FolderMy.ToString(), file, title, createNewIfExist, keepConvertStatus); + return InsertFile(GlobalFolderHelper.FolderMy, file, title, createNewIfExist, keepConvertStatus); } /// @@ -416,9 +399,9 @@ namespace ASC.Api.Documents /// Uploads /// [Create("@common/insert")] - public FileWrapper InsertFileToCommon(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + public FileWrapper InsertFileToCommon(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { - return InsertFile(GlobalFolderHelper.FolderCommon.ToString(), file, title, createNewIfExist, keepConvertStatus); + return InsertFile(GlobalFolderHelper.FolderCommon, file, title, createNewIfExist, keepConvertStatus); } /// @@ -434,19 +417,13 @@ namespace ASC.Api.Documents [Create("{folderId}/insert")] public FileWrapper InsertFile(string folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { - try - { - var resultFile = FileUploader.Exec(folderId, title, file.Length, file, createNewIfExist ?? !FilesSettingsHelper.UpdateIfExist, !keepConvertStatus); - return FileWrapperHelper.Get(resultFile); - } - catch (FileNotFoundException e) - { - throw new ItemNotFoundException("File not found", e); - } - catch (DirectoryNotFoundException e) - { - throw new ItemNotFoundException("Folder not found", e); - } + return FilesControllerHelperString.InsertFile(folderId, file, title, createNewIfExist, keepConvertStatus); + } + + [Create("{folderId:int}/insert")] + public FileWrapper InsertFile(int folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + { + return FilesControllerHelperInt.InsertFile(folderId, file, title, createNewIfExist, keepConvertStatus); } /// @@ -460,15 +437,13 @@ namespace ASC.Api.Documents [Update("{fileId}/update")] public FileWrapper UpdateFileStream(Stream file, string fileId, bool encrypted = false) { - try - { - var resultFile = FileStorageService.UpdateFileStream(fileId, file, encrypted); - return FileWrapperHelper.Get(resultFile); - } - catch (FileNotFoundException e) - { - throw new ItemNotFoundException("File not found", e); - } + return FilesControllerHelperString.UpdateFileStream(file, fileId, encrypted); + } + + [Update("{fileId:int}/update")] + public FileWrapper UpdateFileStream(Stream file, int fileId, bool encrypted = false) + { + return FilesControllerHelperInt.UpdateFileStream(file, fileId, encrypted); } @@ -486,7 +461,13 @@ namespace ASC.Api.Documents [Update("file/{fileId}/saveediting")] public FileWrapper SaveEditing(string fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) { - return FileWrapperHelper.Get(FileStorageService.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave)); + return FilesControllerHelperString.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave); + } + + [Update("file/{fileId:int}/saveediting")] + public FileWrapper SaveEditing(int fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) + { + return FilesControllerHelperInt.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave); } /// @@ -500,7 +481,13 @@ namespace ASC.Api.Documents [Create("file/{fileId}/startedit")] public string StartEdit(string fileId, bool editingAlone, string doc) { - return FileStorageService.StartEdit(fileId, editingAlone, doc); + return FilesControllerHelperString.StartEdit(fileId, editingAlone, doc); + } + + [Create("file/{fileId:int}/startedit")] + public string StartEdit(int fileId, bool editingAlone, string doc) + { + return FilesControllerHelperInt.StartEdit(fileId, editingAlone, doc); } /// @@ -516,7 +503,13 @@ namespace ASC.Api.Documents [Read("file/{fileId}/trackeditfile")] public KeyValuePair TrackEditFile(string fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish) { - return FileStorageService.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish); + return FilesControllerHelperString.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish); + } + + [Read("file/{fileId:int}/trackeditfile")] + public KeyValuePair TrackEditFile(int fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish) + { + return FilesControllerHelperInt.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish); } /// @@ -530,10 +523,13 @@ namespace ASC.Api.Documents [Read("file/{fileId}/openedit")] public Configuration OpenEdit(string fileId, int version, string doc) { - DocumentServiceHelper.GetParams(fileId, version, doc, true, true, true, out var configuration); - configuration.Type = EditorType.External; - configuration.Token = DocumentServiceHelper.GetSignature(configuration); - return configuration; + return FilesControllerHelperString.OpenEdit(fileId, version, doc); + } + + [Read("file/{fileId:int}/openedit")] + public Configuration OpenEdit(int fileId, int version, string doc) + { + return FilesControllerHelperInt.OpenEdit(fileId, version, doc); } @@ -572,43 +568,13 @@ namespace ASC.Api.Documents [Create("{folderId}/upload/create_session")] public object CreateUploadSession(string folderId, string fileName, long fileSize, string relativePath, bool encrypted) { - var file = FileUploader.VerifyChunkedUpload(folderId, fileName, fileSize, FilesSettingsHelper.UpdateIfExist, relativePath); + return FilesControllerHelperString.CreateUploadSession(folderId, fileName, fileSize, relativePath, encrypted); + } - if (FilesLinkUtility.IsLocalFileUploader) - { - var session = FileUploader.InitiateUpload(file.FolderID.ToString(), (file.ID ?? "").ToString(), file.Title, file.ContentLength, encrypted); - - var response = ChunkedUploadSessionHelper.ToResponseObject(session, true); - return new - { - success = true, - data = response - }; - } - - var createSessionUrl = FilesLinkUtility.GetInitiateUploadSessionUrl(TenantManager.GetCurrentTenant().TenantId, file.FolderID, file.ID, file.Title, file.ContentLength, encrypted, SecurityContext); - var request = (HttpWebRequest)WebRequest.Create(createSessionUrl); - request.Method = "POST"; - request.ContentLength = 0; - - // hack for uploader.onlyoffice.com in api requests - var rewriterHeader = ApiContext.HttpContext.Request.Headers[HttpRequestExtensions.UrlRewriterHeader]; - if (!string.IsNullOrEmpty(rewriterHeader)) - { - request.Headers[HttpRequestExtensions.UrlRewriterHeader] = rewriterHeader; - } - - // hack. http://ubuntuforums.org/showthread.php?t=1841740 - if (WorkContext.IsMono) - { - ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; - } - - using (var response = request.GetResponse()) - using (var responseStream = response.GetResponseStream()) - { - return JObject.Parse(new StreamReader(responseStream).ReadToEnd()); //result is json string - } + [Create("{folderId:int}/upload/create_session")] + public object CreateUploadSession(int folderId, string fileName, long fileSize, string relativePath, bool encrypted) + { + return FilesControllerHelperInt.CreateUploadSession(folderId, fileName, fileSize, relativePath, encrypted); } /// @@ -620,9 +586,9 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@my/text")] - public FileWrapper CreateTextFileInMy(string title, string content) + public FileWrapper CreateTextFileInMy(string title, string content) { - return CreateTextFile(GlobalFolderHelper.FolderMy.ToString(), title, content); + return CreateTextFile(GlobalFolderHelper.FolderMy, title, content); } /// @@ -634,9 +600,9 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@common/text")] - public FileWrapper CreateTextFileInCommon(string title, string content) + public FileWrapper CreateTextFileInCommon(string title, string content) { - return CreateTextFile(GlobalFolderHelper.FolderCommon.ToString(), title, content); + return CreateTextFile(GlobalFolderHelper.FolderCommon, title, content); } /// @@ -651,28 +617,13 @@ namespace ASC.Api.Documents [Create("{folderId}/text")] public FileWrapper CreateTextFile(string folderId, string title, string content) { - if (title == null) throw new ArgumentNullException("title"); - //Try detect content - var extension = ".txt"; - if (!string.IsNullOrEmpty(content)) - { - if (Regex.IsMatch(content, @"<([^\s>]*)(\s[^<]*)>")) - { - extension = ".html"; - } - } - return CreateFile(folderId, title, content, extension); + return FilesControllerHelperString.CreateTextFile(folderId, title, content); } - private FileWrapper CreateFile(T folderId, string title, string content, string extension) + [Create("{folderId:int}/text")] + public FileWrapper CreateTextFile(int folderId, string title, string content) { - using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) - { - var file = FileUploader.Exec(folderId, - title.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? title : (title + extension), - memStream.Length, memStream); - return FileWrapperHelper.Get(file); - } + return FilesControllerHelperInt.CreateTextFile(folderId, title, content); } /// @@ -687,8 +638,13 @@ namespace ASC.Api.Documents [Create("{folderId}/html")] public FileWrapper CreateHtmlFile(string folderId, string title, string content) { - if (title == null) throw new ArgumentNullException("title"); - return CreateFile(folderId, title, content, ".html"); + return FilesControllerHelperString.CreateHtmlFile(folderId, title, content); + } + + [Create("{folderId:int}/html")] + public FileWrapper CreateHtmlFile(int folderId, string title, string content) + { + return FilesControllerHelperInt.CreateHtmlFile(folderId, title, content); } /// @@ -700,9 +656,9 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@my/html")] - public FileWrapper CreateHtmlFileInMy(string title, string content) + public FileWrapper CreateHtmlFileInMy(string title, string content) { - return CreateHtmlFile(GlobalFolderHelper.FolderMy.ToString(), title, content); + return CreateHtmlFile(GlobalFolderHelper.FolderMy, title, content); } @@ -715,9 +671,9 @@ namespace ASC.Api.Documents /// File contents /// Folder contents [Create("@common/html")] - public FileWrapper CreateHtmlFileInCommon(string title, string content) + public FileWrapper CreateHtmlFileInCommon(string title, string content) { - return CreateHtmlFile(GlobalFolderHelper.FolderCommon.ToString(), title, content); + return CreateHtmlFile(GlobalFolderHelper.FolderCommon, title, content); } @@ -734,10 +690,16 @@ namespace ASC.Api.Documents [Create("folder/{folderId}")] public FolderWrapper CreateFolder(string folderId, string title) { - var folder = FileStorageService.CreateNewFolder(folderId, title); - return FolderWrapperHelper.Get(folder); + return FilesControllerHelperString.CreateFolder(folderId, title); } + [Create("folder/{folderId:int}")] + public FolderWrapper CreateFolder(int folderId, string title) + { + return FilesControllerHelperInt.CreateFolder(folderId, title); + } + + /// /// Creates a new file in the 'My Documents' section with the title sent in the request /// @@ -747,9 +709,9 @@ namespace ASC.Api.Documents /// 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 [Create("@my/file")] - public FileWrapper CreateFile(string title) + public FileWrapper CreateFile(string title) { - return CreateFile(GlobalFolderHelper.FolderMy.ToString(), title); + return CreateFile(GlobalFolderHelper.FolderMy, title); } /// @@ -764,8 +726,13 @@ namespace ASC.Api.Documents [Create("{folderId}/file")] public FileWrapper CreateFile(string folderId, string title) { - var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); - return FileWrapperHelper.Get(file); + return FilesControllerHelperString.CreateFile(folderId, title); + } + + [Create("{folderId:int}/file")] + public FileWrapper CreateFile(int folderId, string title) + { + return FilesControllerHelperInt.CreateFile(folderId, title); } /// @@ -781,8 +748,13 @@ namespace ASC.Api.Documents [Update("folder/{folderId}")] public FolderWrapper RenameFolder(string folderId, string title) { - var folder = FileStorageService.FolderRename(folderId, title); - return FolderWrapperHelper.Get(folder); + return FilesControllerHelperString.RenameFolder(folderId, title); + } + + [Update("folder/{folderId:int}")] + public FolderWrapper RenameFolder(int folderId, string title) + { + return FilesControllerHelperInt.RenameFolder(folderId, title); } /// @@ -794,9 +766,13 @@ namespace ASC.Api.Documents [Read("folder/{folderId}")] public FolderWrapper GetFolderInfo(string folderId) { - var folder = FileStorageService.GetFolder(folderId).NotFoundIfNull("Folder not found"); + return FilesControllerHelperString.GetFolderInfo(folderId); + } - return FolderWrapperHelper.Get(folder); + [Read("folder/{folderId:int}")] + public FolderWrapper GetFolderInfo(int folderId) + { + return FilesControllerHelperInt.GetFolderInfo(folderId); } /// @@ -808,7 +784,13 @@ namespace ASC.Api.Documents [Read("folder/{folderId}/path")] public IEnumerable> GetFolderPath(string folderId) { - return EntryManager.GetBreadCrumbs(folderId).Select(FolderWrapperHelper.Get); + return FilesControllerHelperString.GetFolderPath(folderId); + } + + [Read("folder/{folderId:int}/path")] + public IEnumerable> GetFolderPath(int folderId) + { + return FilesControllerHelperInt.GetFolderPath(folderId); } /// @@ -820,21 +802,13 @@ namespace ASC.Api.Documents [Read("file/{fileId}", DisableFormat = true)] public FileWrapper GetFileInfo(string fileId, int version = -1) { - var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); - return FileWrapperHelper.Get(file); + return FilesControllerHelperString.GetFileInfo(fileId, version); } - /// - /// Returns a detailed information about the file with the ID specified in the request - /// - /// File information - /// Files - /// File info - [Read("file/{fileId:int}")] + [Read("file/{fileId:int}", DisableFormat = true)] public FileWrapper GetFileInfo(int fileId, int version = -1) { - var file = FileStorageServiceInt.GetFile(fileId, version).NotFoundIfNull("File not found"); - return FileWrapperHelper.Get(file); + return FilesControllerHelperInt.GetFileInfo(fileId, version); } /// @@ -849,13 +823,13 @@ namespace ASC.Api.Documents [Update("file/{fileId}")] public FileWrapper UpdateFile(string fileId, string title, int lastVersion) { - if (!string.IsNullOrEmpty(title)) - FileStorageService.FileRename(fileId.ToString(CultureInfo.InvariantCulture), title); + return FilesControllerHelperString.UpdateFile(fileId, title, lastVersion); + } - if (lastVersion > 0) - FileStorageService.UpdateToVersion(fileId.ToString(CultureInfo.InvariantCulture), lastVersion); - - return GetFileInfo(fileId); + [Update("file/{fileId:int}")] + public FileWrapper UpdateFile(int fileId, string title, int lastVersion) + { + return FilesControllerHelperInt.UpdateFile(fileId, title, lastVersion); } /// @@ -870,14 +844,13 @@ namespace ASC.Api.Documents [Delete("file/{fileId}")] public IEnumerable> DeleteFile(string fileId, bool deleteAfter, bool immediately) { - var model = new DeleteBatchModel - { - FileIds = new List { fileId }, - DeleteAfter = deleteAfter, - Immediately = immediately - }; + return FilesControllerHelperString.DeleteFile(fileId, deleteAfter, immediately); + } - return DeleteBatchItems(model); + [Delete("file/{fileId:int}")] + public IEnumerable> DeleteFile(int fileId, bool deleteAfter, bool immediately) + { + return FilesControllerHelperInt.DeleteFile(fileId, deleteAfter, immediately); } /// @@ -888,9 +861,15 @@ namespace ASC.Api.Documents /// /// Operation result [Update("file/{fileId}/checkconversion")] - public IEnumerable StartConversion(string fileId) + public IEnumerable> StartConversion(string fileId) { - return CheckConversion(fileId, true); + return FilesControllerHelperString.StartConversion(fileId); + } + + [Update("file/{fileId:int}/checkconversion")] + public IEnumerable> StartConversion(int fileId) + { + return FilesControllerHelperInt.StartConversion(fileId); } /// @@ -902,30 +881,15 @@ namespace ASC.Api.Documents /// /// Operation result [Read("file/{fileId}/checkconversion")] - public IEnumerable CheckConversion(string fileId, bool start) + public IEnumerable> CheckConversion(string fileId, bool start) { - return FileStorageService.CheckConversion(new ItemList> - { - new ItemList { fileId, "0", start.ToString() } - }) - .Select(r => - { - var o = new ConversationResult - { - Id = r.Id, - Error = r.Error, - OperationType = r.OperationType, - Processed = r.Processed, - Progress = r.Progress, - Source = r.Source, - }; - if (!string.IsNullOrEmpty(r.Result)) - { - var jResult = JObject.Parse(r.Result); - o.File = GetFileInfo(jResult.Value("id"), jResult.Value("version")); - } - return o; - }); + return FilesControllerHelperString.CheckConversion(fileId, start); + } + + [Read("file/{fileId:int}/checkconversion")] + public IEnumerable> CheckConversion(int fileId, bool start) + { + return FilesControllerHelperInt.CheckConversion(fileId, start); } /// @@ -940,14 +904,13 @@ namespace ASC.Api.Documents [Delete("folder/{folderId}")] public IEnumerable> DeleteFolder(string folderId, bool deleteAfter, bool immediately) { - var model = new DeleteBatchModel - { - FolderIds = new List { folderId }, - DeleteAfter = deleteAfter, - Immediately = immediately - }; + return FilesControllerHelperString.DeleteFolder(folderId, deleteAfter, immediately); + } - return DeleteBatchItems(model); + [Delete("folder/{folderId:int}")] + public IEnumerable> DeleteFolder(int folderId, bool deleteAfter, bool immediately) + { + return FilesControllerHelperInt.DeleteFolder(folderId, deleteAfter, immediately); } /// @@ -959,17 +922,16 @@ namespace ASC.Api.Documents /// File ID list /// Conflicts file ids [Read("fileops/move")] - public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) + public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) { - var itemList = new ItemList(); + return FilesControllerHelperString.MoveOrCopyBatchCheck(batchModel); + } - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - - var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); - - var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); - return entries.Select(x => FileWrapperHelper.Get((File)x)); + [Read("fileops/move")] + [BodySpecific] + public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) + { + return FilesControllerHelperInt.MoveOrCopyBatchCheck(batchModel); } /// @@ -984,14 +946,16 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/move")] - public IEnumerable> MoveBatchItems(BatchModel batchModel) + public IEnumerable> MoveBatchItems(BatchModel batchModel) { - var itemList = new ItemList(); + return FilesControllerHelperString.MoveBatchItems(batchModel); + } - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + [Update("fileops/move")] + [BodySpecific] + public IEnumerable> MoveBatchItems(BatchModel batchModel) + { + return FilesControllerHelperInt.MoveBatchItems(batchModel); } /// @@ -1006,14 +970,16 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/copy")] - public IEnumerable> CopyBatchItems(BatchModel batchModel) + public IEnumerable> CopyBatchItems(BatchModel batchModel) { - var itemList = new ItemList(); + return FilesControllerHelperString.CopyBatchItems(batchModel); + } - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter).Select(FileOperationWraperHelper.Get); + [BodySpecific] + [Update("fileops/copy")] + public IEnumerable> CopyBatchItems(BatchModel batchModel) + { + return FilesControllerHelperInt.CopyBatchItems(batchModel); } /// @@ -1023,14 +989,16 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/markasread")] - public IEnumerable> MarkAsRead(BaseBatchModel model) + public IEnumerable> MarkAsRead(BaseBatchModel model) { - var itemList = new ItemList(); + return FilesControllerHelperString.MarkAsRead(model); + } - itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + [Update("fileops/markasread")] + [BodySpecific] + public IEnumerable> MarkAsRead(BaseBatchModel model) + { + return FilesControllerHelperInt.MarkAsRead(model); } /// @@ -1068,26 +1036,16 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/bulkdownload")] - public IEnumerable> BulkDownload(DownloadModel model) + public IEnumerable> BulkDownload(DownloadModel model) { - var itemList = new Dictionary(); + return FilesControllerHelperString.BulkDownload(model); + } - foreach (var fileId in model.FileConvertIds.Where(fileId => !itemList.ContainsKey(fileId.Key))) - { - itemList.Add("file_" + fileId.Key, fileId.Value); - } - - foreach (var fileId in model.FileIds.Where(fileId => !itemList.ContainsKey(fileId))) - { - itemList.Add("file_" + fileId, string.Empty); - } - - foreach (var folderId in model.FolderIds.Where(folderId => !itemList.ContainsKey(folderId))) - { - itemList.Add("folder_" + folderId, string.Empty); - } - - return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); + [BodySpecific] + [Update("fileops/bulkdownload")] + public IEnumerable> BulkDownload(DownloadModel model) + { + return FilesControllerHelperInt.BulkDownload(model); } /// @@ -1101,7 +1059,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/delete")] - public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) + public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) { var itemList = new ItemList(); @@ -1133,8 +1091,13 @@ namespace ASC.Api.Documents [Read("file/{fileId}/history")] public IEnumerable> GetFileVersionInfo(string fileId) { - var files = FileStorageService.GetFileHistory(fileId); - return files.Select(FileWrapperHelper.Get); + return FilesControllerHelperString.GetFileVersionInfo(fileId); + } + + [Read("file/{fileId:int}/history")] + public IEnumerable> GetFileVersionInfo(int fileId) + { + return FilesControllerHelperInt.GetFileVersionInfo(fileId); } /// @@ -1148,8 +1111,12 @@ namespace ASC.Api.Documents [Update("file/{fileId}/history")] public IEnumerable> ChangeHistory(string fileId, int version, bool continueVersion) { - var history = FileStorageService.CompleteVersion(fileId, version, continueVersion).Value; - return history.Select(FileWrapperHelper.Get); + return FilesControllerHelperString.ChangeHistory(fileId, version, continueVersion); + } + [Update("file/{fileId:int}/history")] + public IEnumerable> ChangeHistory(int fileId, int version, bool continueVersion) + { + return FilesControllerHelperInt.ChangeHistory(fileId, version, continueVersion); } /// @@ -1162,8 +1129,13 @@ namespace ASC.Api.Documents [Read("file/{fileId}/share")] public IEnumerable GetFileSecurityInfo(string fileId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); - return fileShares.Select(FileShareWrapperHelper.Get); + return FilesControllerHelperString.GetFileSecurityInfo(fileId); + } + + [Read("file/{fileId:int}/share")] + public IEnumerable GetFileSecurityInfo(int fileId) + { + return FilesControllerHelperInt.GetFileSecurityInfo(fileId); } /// @@ -1176,8 +1148,13 @@ namespace ASC.Api.Documents [Read("folder/{folderId}/share")] public IEnumerable GetFolderSecurityInfo(string folderId) { - var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); - return fileShares.Select(FileShareWrapperHelper.Get); + return FilesControllerHelperString.GetFolderSecurityInfo(folderId); + } + + [Read("folder/{folderId:int}/share")] + public IEnumerable GetFolderSecurityInfo(int folderId) + { + return FilesControllerHelperInt.GetFolderSecurityInfo(folderId); } /// @@ -1196,18 +1173,13 @@ namespace ASC.Api.Documents [Update("file/{fileId}/share")] public IEnumerable SetFileSecurityInfo(string fileId, IEnumerable share, bool notify, string sharingMessage) { - if (share != null && share.Any()) - { - var list = new ItemList(share.Select(FileShareParamsHelper.ToAceObject)); - var aceCollection = new AceCollection - { - Entries = new ItemList { "file_" + fileId }, - Aces = list, - Message = sharingMessage - }; - FileStorageService.SetAceObject(aceCollection, notify); - } - return GetFileSecurityInfo(fileId); + return FilesControllerHelperString.SetFileSecurityInfo(fileId, share, notify, sharingMessage); + } + + [Update("file/{fileId:int}/share")] + public IEnumerable SetFileSecurityInfo(int fileId, IEnumerable share, bool notify, string sharingMessage) + { + return FilesControllerHelperInt.SetFileSecurityInfo(fileId, share, notify, sharingMessage); } /// @@ -1226,19 +1198,12 @@ namespace ASC.Api.Documents [Update("folder/{folderId}/share")] public IEnumerable SetFolderSecurityInfo(string folderId, IEnumerable share, bool notify, string sharingMessage) { - if (share != null && share.Any()) - { - var list = new ItemList(share.Select(FileShareParamsHelper.ToAceObject)); - var aceCollection = new AceCollection - { - Entries = new ItemList { "folder_" + folderId }, - Aces = list, - Message = sharingMessage - }; - FileStorageService.SetAceObject(aceCollection, notify); - } - - return GetFolderSecurityInfo(folderId); + return FilesControllerHelperString.SetFolderSecurityInfo(folderId, share, notify, sharingMessage); + } + [Update("folder/{folderId:int}/share")] + public IEnumerable SetFolderSecurityInfo(int folderId, IEnumerable share, bool notify, string sharingMessage) + { + return FilesControllerHelperInt.SetFolderSecurityInfo(folderId, share, notify, sharingMessage); } /// @@ -1250,12 +1215,12 @@ namespace ASC.Api.Documents /// Sharing /// Shared file information [Delete("share")] - public bool RemoveSecurityInfo(BaseBatchModel model) + public bool RemoveSecurityInfo(BaseBatchModel model) { var itemList = new ItemList(); - itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); + itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); FileStorageService.RemoveAce(itemList); @@ -1789,7 +1754,7 @@ namespace ASC.Api.Documents /// Result of file conversation operation. /// [DataContract(Name = "operation_result", Namespace = "")] - public class ConversationResult + public class ConversationResult { /// /// Operation Id. @@ -1819,7 +1784,7 @@ namespace ASC.Api.Documents /// Result file of operation. /// [DataMember(Name = "result")] - public FileWrapper File { get; set; } + public FileWrapper File { get; set; } /// /// Error during conversation. @@ -1839,41 +1804,47 @@ namespace ASC.Api.Documents { public static DIHelper AddDocumentsControllerService(this DIHelper services) { - return services - .AddEasyBibHelperService() - .AddWordpressTokenService() - .AddWordpressHelperService() - .AddFolderContentWrapperHelperService() - .AddFileUploaderService() - .AddFileShareParamsService() - .AddFileShareWrapperService() - .AddFileOperationWraperHelperService() - .AddFileWrapperHelperService() - .AddFolderWrapperHelperService() - .AddConsumerFactoryService() - .AddDocumentServiceConnectorService() - .AddCommonLinkUtilityService() - .AddMessageServiceService() - .AddThirdpartyConfigurationService() - .AddCoreBaseSettingsService() - .AddWebItemSecurity() - .AddUserManagerService() - .AddEntryManagerService() - .AddTenantManagerService() - .AddSecurityContextService() - .AddDocumentServiceHelperService() - .AddFilesLinkUtilityService() - .AddApiContextService() - .AddFileStorageService() - .AddGlobalFolderHelperService() - .AddFilesSettingsHelperService() - .AddBoxLoginProviderService() - .AddDropboxLoginProviderService() - .AddOneDriveLoginProviderService() - .AddGoogleLoginProviderService() - .AddChunkedUploadSessionHelperService() - .AddProductEntryPointService() - ; + return services.AddFilesControllerHelperService(); + } + } + + public class BodySpecificAttribute : Attribute, IActionConstraint + { + public BodySpecificAttribute() + { + } + + public int Order + { + get + { + return 0; + } + } + + public bool Accept(ActionConstraintContext context) + { + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true + }; + + try + { + context.RouteContext.HttpContext.Request.EnableBuffering(); + _ = JsonSerializer.DeserializeAsync>(context.RouteContext.HttpContext.Request.Body, options).Result; + return true; + } + catch + { + return false; + } + finally + { + context.RouteContext.HttpContext.Request.Body.Seek(0, SeekOrigin.Begin); + } + } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs new file mode 100644 index 0000000000..1ee2771fec --- /dev/null +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -0,0 +1,1019 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; + +using ASC.Api.Core; +using ASC.Api.Documents; +using ASC.Api.Utils; +using ASC.Common; +using ASC.Common.Web; +using ASC.Core; +using ASC.Core.Common.Configuration; +using ASC.Core.Users; +using ASC.FederatedLogin.Helpers; +using ASC.FederatedLogin.LoginProviders; +using ASC.Files.Core; +using ASC.Files.Model; +using ASC.MessagingSystem; +using ASC.Web.Core; +using ASC.Web.Core.Files; +using ASC.Web.Files.Classes; +using ASC.Web.Files.Configuration; +using ASC.Web.Files.Helpers; +using ASC.Web.Files.Services.DocumentService; +using ASC.Web.Files.Services.WCFService; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Utility; + +using Microsoft.AspNetCore.Http; + +using Newtonsoft.Json.Linq; + +using static ASC.Api.Documents.FilesController; + +using FileShare = ASC.Files.Core.Security.FileShare; +using MimeMapping = ASC.Common.Web.MimeMapping; +using SortedByType = ASC.Files.Core.SortedByType; + +namespace ASC.Files.Helpers +{ + public class FilesControllerHelper + { + private readonly ApiContext ApiContext; + private readonly FileStorageService FileStorageService; + + public GlobalFolderHelper GlobalFolderHelper { get; } + public FileWrapperHelper FileWrapperHelper { get; } + public FilesSettingsHelper FilesSettingsHelper { get; } + public FilesLinkUtility FilesLinkUtility { get; } + public FileUploader FileUploader { get; } + public DocumentServiceHelper DocumentServiceHelper { get; } + public TenantManager TenantManager { get; } + public SecurityContext SecurityContext { get; } + public FolderWrapperHelper FolderWrapperHelper { get; } + public FileOperationWraperHelper FileOperationWraperHelper { get; } + public FileShareWrapperHelper FileShareWrapperHelper { get; } + public FileShareParamsHelper FileShareParamsHelper { get; } + public EntryManager EntryManager { get; } + public UserManager UserManager { get; } + public WebItemSecurity WebItemSecurity { get; } + public CoreBaseSettings CoreBaseSettings { get; } + public ThirdpartyConfiguration ThirdpartyConfiguration { get; } + public BoxLoginProvider BoxLoginProvider { get; } + public DropboxLoginProvider DropboxLoginProvider { get; } + public GoogleLoginProvider GoogleLoginProvider { get; } + public OneDriveLoginProvider OneDriveLoginProvider { get; } + public MessageService MessageService { get; } + public CommonLinkUtility CommonLinkUtility { get; } + public DocumentServiceConnector DocumentServiceConnector { get; } + public FolderContentWrapperHelper FolderContentWrapperHelper { get; } + public WordpressToken WordpressToken { get; } + public WordpressHelper WordpressHelper { get; } + public ConsumerFactory ConsumerFactory { get; } + public EasyBibHelper EasyBibHelper { get; } + public ChunkedUploadSessionHelper ChunkedUploadSessionHelper { get; } + public ProductEntryPoint ProductEntryPoint { get; } + + /// + /// + /// + /// + public FilesControllerHelper( + ApiContext context, + FileStorageService fileStorageService, + GlobalFolderHelper globalFolderHelper, + FileWrapperHelper fileWrapperHelper, + FilesSettingsHelper filesSettingsHelper, + FilesLinkUtility filesLinkUtility, + FileUploader fileUploader, + DocumentServiceHelper documentServiceHelper, + TenantManager tenantManager, + SecurityContext securityContext, + FolderWrapperHelper folderWrapperHelper, + FileOperationWraperHelper fileOperationWraperHelper, + FileShareWrapperHelper fileShareWrapperHelper, + FileShareParamsHelper fileShareParamsHelper, + EntryManager entryManager, + UserManager userManager, + WebItemSecurity webItemSecurity, + CoreBaseSettings coreBaseSettings, + ThirdpartyConfiguration thirdpartyConfiguration, + MessageService messageService, + CommonLinkUtility commonLinkUtility, + DocumentServiceConnector documentServiceConnector, + FolderContentWrapperHelper folderContentWrapperHelper, + WordpressToken wordpressToken, + WordpressHelper wordpressHelper, + ConsumerFactory consumerFactory, + EasyBibHelper easyBibHelper, + ChunkedUploadSessionHelper chunkedUploadSessionHelper, + ProductEntryPoint productEntryPoint) + { + ApiContext = context; + FileStorageService = fileStorageService; + GlobalFolderHelper = globalFolderHelper; + FileWrapperHelper = fileWrapperHelper; + FilesSettingsHelper = filesSettingsHelper; + FilesLinkUtility = filesLinkUtility; + FileUploader = fileUploader; + DocumentServiceHelper = documentServiceHelper; + TenantManager = tenantManager; + SecurityContext = securityContext; + FolderWrapperHelper = folderWrapperHelper; + FileOperationWraperHelper = fileOperationWraperHelper; + FileShareWrapperHelper = fileShareWrapperHelper; + FileShareParamsHelper = fileShareParamsHelper; + EntryManager = entryManager; + UserManager = userManager; + WebItemSecurity = webItemSecurity; + CoreBaseSettings = coreBaseSettings; + ThirdpartyConfiguration = thirdpartyConfiguration; + ConsumerFactory = consumerFactory; + BoxLoginProvider = ConsumerFactory.Get(); + DropboxLoginProvider = ConsumerFactory.Get(); + GoogleLoginProvider = ConsumerFactory.Get(); + OneDriveLoginProvider = ConsumerFactory.Get(); + MessageService = messageService; + CommonLinkUtility = commonLinkUtility; + DocumentServiceConnector = documentServiceConnector; + FolderContentWrapperHelper = folderContentWrapperHelper; + WordpressToken = wordpressToken; + WordpressHelper = wordpressHelper; + EasyBibHelper = easyBibHelper; + ChunkedUploadSessionHelper = chunkedUploadSessionHelper; + ProductEntryPoint = productEntryPoint; + } + + public FolderContentWrapper GetFolder(T folderId, Guid userIdOrGroupId, FilterType filterType) + { + return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); + } + + public List> UploadFile(T folderId, UploadModel uploadModel) + { + if (uploadModel.StoreOriginalFileFlag.HasValue) + { + FilesSettingsHelper.StoreOriginalFiles = uploadModel.StoreOriginalFileFlag.Value; + } + + if (uploadModel.Files != null && uploadModel.Files.Any()) + { + if (uploadModel.Files.Count() == 1) + { + //Only one file. return it + var postedFile = uploadModel.Files.First(); + return new List> + { + InsertFile(folderId, postedFile.OpenReadStream(), postedFile.FileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus) + }; + } + //For case with multiple files + return uploadModel.Files.Select(postedFile => InsertFile(folderId, postedFile.OpenReadStream(), postedFile.FileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus)).ToList(); + } + if (uploadModel.File != null) + { + var fileName = "file" + MimeMapping.GetExtention(uploadModel.ContentType.MediaType); + if (uploadModel.ContentDisposition != null) + { + fileName = uploadModel.ContentDisposition.FileName; + } + + return new List> + { + InsertFile(folderId, uploadModel.File, fileName, uploadModel.CreateNewIfExist, uploadModel.KeepConvertStatus) + }; + } + throw new InvalidOperationException("No input files"); + } + + public FileWrapper InsertFile(T folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) + { + try + { + var resultFile = FileUploader.Exec(folderId, title, file.Length, file, createNewIfExist ?? !FilesSettingsHelper.UpdateIfExist, !keepConvertStatus); + return FileWrapperHelper.Get(resultFile); + } + catch (FileNotFoundException e) + { + throw new ItemNotFoundException("File not found", e); + } + catch (DirectoryNotFoundException e) + { + throw new ItemNotFoundException("Folder not found", e); + } + } + + public FileWrapper UpdateFileStream(Stream file, T fileId, bool encrypted = false) + { + try + { + var resultFile = FileStorageService.UpdateFileStream(fileId, file, encrypted); + return FileWrapperHelper.Get(resultFile); + } + catch (FileNotFoundException e) + { + throw new ItemNotFoundException("File not found", e); + } + } + + public FileWrapper SaveEditing(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) + { + return FileWrapperHelper.Get(FileStorageService.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave)); + } + + public string StartEdit(T fileId, bool editingAlone, string doc) + { + return FileStorageService.StartEdit(fileId, editingAlone, doc); + } + + public KeyValuePair TrackEditFile(T fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish) + { + return FileStorageService.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish); + } + + public Configuration OpenEdit(T fileId, int version, string doc) + { + DocumentServiceHelper.GetParams(fileId, version, doc, true, true, true, out var configuration); + configuration.Type = EditorType.External; + configuration.Token = DocumentServiceHelper.GetSignature(configuration); + return configuration; + } + + public object CreateUploadSession(T folderId, string fileName, long fileSize, string relativePath, bool encrypted) + { + var file = FileUploader.VerifyChunkedUpload(folderId, fileName, fileSize, FilesSettingsHelper.UpdateIfExist, relativePath); + + if (FilesLinkUtility.IsLocalFileUploader) + { + var session = FileUploader.InitiateUpload(file.FolderID.ToString(), (file.ID ?? default).ToString(), file.Title, file.ContentLength, encrypted); + + var response = ChunkedUploadSessionHelper.ToResponseObject(session, true); + return new + { + success = true, + data = response + }; + } + + var createSessionUrl = FilesLinkUtility.GetInitiateUploadSessionUrl(TenantManager.GetCurrentTenant().TenantId, file.FolderID, file.ID, file.Title, file.ContentLength, encrypted, SecurityContext); + var request = (HttpWebRequest)WebRequest.Create(createSessionUrl); + request.Method = "POST"; + request.ContentLength = 0; + + // hack for uploader.onlyoffice.com in api requests + var rewriterHeader = ApiContext.HttpContext.Request.Headers[HttpRequestExtensions.UrlRewriterHeader]; + if (!string.IsNullOrEmpty(rewriterHeader)) + { + request.Headers[HttpRequestExtensions.UrlRewriterHeader] = rewriterHeader; + } + + // hack. http://ubuntuforums.org/showthread.php?t=1841740 + if (WorkContext.IsMono) + { + ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true; + } + + using (var response = request.GetResponse()) + using (var responseStream = response.GetResponseStream()) + { + return JObject.Parse(new StreamReader(responseStream).ReadToEnd()); //result is json string + } + } + + public FileWrapper CreateTextFile(T folderId, string title, string content) + { + if (title == null) throw new ArgumentNullException("title"); + //Try detect content + var extension = ".txt"; + if (!string.IsNullOrEmpty(content)) + { + if (Regex.IsMatch(content, @"<([^\s>]*)(\s[^<]*)>")) + { + extension = ".html"; + } + } + return CreateFile(folderId, title, content, extension); + } + + private FileWrapper CreateFile(T folderId, string title, string content, string extension) + { + using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content))) + { + var file = FileUploader.Exec(folderId, + title.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? title : (title + extension), + memStream.Length, memStream); + return FileWrapperHelper.Get(file); + } + } + + public FileWrapper CreateHtmlFile(T folderId, string title, string content) + { + if (title == null) throw new ArgumentNullException("title"); + return CreateFile(folderId, title, content, ".html"); + } + + public FolderWrapper CreateFolder(T folderId, string title) + { + var folder = FileStorageService.CreateNewFolder(folderId, title); + return FolderWrapperHelper.Get(folder); + } + + public FileWrapper CreateFile(T folderId, string title) + { + var file = FileStorageService.CreateNewFile(new FileModel { ParentId = folderId, Title = title }); + return FileWrapperHelper.Get(file); + } + + public FolderWrapper RenameFolder(T folderId, string title) + { + var folder = FileStorageService.FolderRename(folderId, title); + return FolderWrapperHelper.Get(folder); + } + + public FolderWrapper GetFolderInfo(T folderId) + { + var folder = FileStorageService.GetFolder(folderId).NotFoundIfNull("Folder not found"); + + return FolderWrapperHelper.Get(folder); + } + + public IEnumerable> GetFolderPath(T folderId) + { + return EntryManager.GetBreadCrumbs(folderId).Select(FolderWrapperHelper.Get); + } + + public FileWrapper GetFileInfo(T fileId, int version = -1) + { + var file = FileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found"); + return FileWrapperHelper.Get(file); + } + + public FileWrapper UpdateFile(T fileId, string title, int lastVersion) + { + if (!string.IsNullOrEmpty(title)) + FileStorageService.FileRename(fileId, title); + + if (lastVersion > 0) + FileStorageService.UpdateToVersion(fileId, lastVersion); + + return GetFileInfo(fileId); + } + + public IEnumerable> DeleteFile(T fileId, bool deleteAfter, bool immediately) + { + var model = new DeleteBatchModel + { + FileIds = new List { fileId }, + DeleteAfter = deleteAfter, + Immediately = immediately + }; + + return DeleteBatchItems(model); + } + + public IEnumerable> StartConversion(T fileId) + { + return CheckConversion(fileId, true); + } + + public IEnumerable> CheckConversion(T fileId, bool start) + { + return FileStorageService.CheckConversion(new ItemList> + { + new ItemList { fileId.ToString(), "0", start.ToString() } + }) + .Select(r => + { + var o = new ConversationResult + { + Id = r.Id, + Error = r.Error, + OperationType = r.OperationType, + Processed = r.Processed, + Progress = r.Progress, + Source = r.Source, + }; + if (!string.IsNullOrEmpty(r.Result)) + { + var jResult = JObject.Parse(r.Result); + o.File = GetFileInfo(jResult.Value("id"), jResult.Value("version")); + } + return o; + }); + } + + public IEnumerable> DeleteFolder(T folderId, bool deleteAfter, bool immediately) + { + var model = new DeleteBatchModel + { + FolderIds = new List { folderId }, + DeleteAfter = deleteAfter, + Immediately = immediately + }; + + return DeleteBatchItems(model); + } + + public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) + { + var itemList = new ItemList(); + + itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); + + var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); + + var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); + return entries.Select(x => FileWrapperHelper.Get((File)x)); + } + + public IEnumerable> MoveBatchItems(BatchModel batchModel) + { + var itemList = new ItemList(); + + itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); + + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter) + .Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> CopyBatchItems(BatchModel batchModel) + { + var itemList = new ItemList(); + + itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); + + return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter) + .Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> MarkAsRead(BaseBatchModel model) + { + var itemList = new ItemList(); + + itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); + + return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> TerminateTasks() + { + return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> GetOperationStatuses() + { + return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> BulkDownload(DownloadModel model) + { + var itemList = new Dictionary(); + + foreach (var fileId in model.FileConvertIds.Where(fileId => !itemList.ContainsKey(fileId.Key))) + { + itemList.Add("file_" + fileId.Key, fileId.Value); + } + + foreach (var fileId in model.FileIds.Where(fileId => !itemList.ContainsKey(fileId.ToString()))) + { + itemList.Add("file_" + fileId, string.Empty); + } + + foreach (var folderId in model.FolderIds.Where(folderId => !itemList.ContainsKey(folderId.ToString()))) + { + itemList.Add("folder_" + folderId, string.Empty); + } + + return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) + { + var itemList = new ItemList(); + + itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); + + return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately) + .Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> EmptyTrash() + { + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + } + + public IEnumerable> GetFileVersionInfo(T fileId) + { + var files = FileStorageService.GetFileHistory(fileId); + return files.Select(FileWrapperHelper.Get); + } + + public IEnumerable> ChangeHistory(T fileId, int version, bool continueVersion) + { + var history = FileStorageService.CompleteVersion(fileId, version, continueVersion).Value; + return history.Select(FileWrapperHelper.Get); + } + + public IEnumerable GetFileSecurityInfo(T fileId) + { + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("file_{0}", fileId) }); + return fileShares.Select(FileShareWrapperHelper.Get); + } + + public IEnumerable GetFolderSecurityInfo(T folderId) + { + var fileShares = FileStorageService.GetSharedInfo(new ItemList { string.Format("folder_{0}", folderId) }); + return fileShares.Select(FileShareWrapperHelper.Get); + } + + public IEnumerable SetFileSecurityInfo(T fileId, IEnumerable share, bool notify, string sharingMessage) + { + if (share != null && share.Any()) + { + var list = new ItemList(share.Select(FileShareParamsHelper.ToAceObject)); + var aceCollection = new AceCollection + { + Entries = new ItemList { "file_" + fileId }, + Aces = list, + Message = sharingMessage + }; + FileStorageService.SetAceObject(aceCollection, notify); + } + return GetFileSecurityInfo(fileId); + } + + public IEnumerable SetFolderSecurityInfo(T folderId, IEnumerable share, bool notify, string sharingMessage) + { + if (share != null && share.Any()) + { + var list = new ItemList(share.Select(FileShareParamsHelper.ToAceObject)); + var aceCollection = new AceCollection + { + Entries = new ItemList { "folder_" + folderId }, + Aces = list, + Message = sharingMessage + }; + FileStorageService.SetAceObject(aceCollection, notify); + } + + return GetFolderSecurityInfo(folderId); + } + + public bool RemoveSecurityInfo(BaseBatchModel model) + { + var itemList = new ItemList(); + + itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); + itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); + + FileStorageService.RemoveAce(itemList); + + return true; + } + + public string GenerateSharedLink(T fileId, FileShare share) + { + var file = GetFileInfo(fileId); + + var objectId = "file_" + file.Id; + var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + if (sharedInfo == null || sharedInfo.Share != share) + { + var list = new ItemList + { + new AceWrapper + { + SubjectId = FileConstant.ShareLinkId, + SubjectGroup = true, + Share = share + } + }; + var aceCollection = new AceCollection + { + Entries = new ItemList { objectId }, + Aces = list + }; + FileStorageService.SetAceObject(aceCollection, false); + sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); + } + + return sharedInfo.Link; + } + + public List> Capabilities() + { + var result = new List>(); + + if (UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor(UserManager) + || (!UserManager.IsUserInGroup(SecurityContext.CurrentAccount.ID, Constants.GroupAdmin.ID) + && !WebItemSecurity.IsProductAdministrator(ProductEntryPoint.ID, SecurityContext.CurrentAccount.ID) + && !FilesSettingsHelper.EnableThirdParty + && !CoreBaseSettings.Personal)) + { + return result; + } + + if (ThirdpartyConfiguration.SupportBoxInclusion) + { + result.Add(new List { "Box", BoxLoginProvider.ClientID, BoxLoginProvider.RedirectUri }); + } + if (ThirdpartyConfiguration.SupportDropboxInclusion) + { + result.Add(new List { "DropboxV2", DropboxLoginProvider.ClientID, DropboxLoginProvider.RedirectUri }); + } + if (ThirdpartyConfiguration.SupportGoogleDriveInclusion) + { + result.Add(new List { "GoogleDrive", GoogleLoginProvider.ClientID, GoogleLoginProvider.RedirectUri }); + } + if (ThirdpartyConfiguration.SupportOneDriveInclusion) + { + result.Add(new List { "OneDrive", OneDriveLoginProvider.ClientID, OneDriveLoginProvider.RedirectUri }); + } + if (ThirdpartyConfiguration.SupportSharePointInclusion) + { + result.Add(new List { "SharePoint" }); + } + if (ThirdpartyConfiguration.SupportYandexInclusion) + { + result.Add(new List { "Yandex" }); + } + if (ThirdpartyConfiguration.SupportWebDavInclusion) + { + result.Add(new List { "WebDav" }); + } + + //Obsolete BoxNet, DropBox, Google, SkyDrive, + + return result; + } + + public FolderWrapper SaveThirdParty( + string url, + string login, + string password, + string token, + bool isCorporate, + string customerTitle, + string providerKey, + string providerId) + { + var thirdPartyParams = new ThirdPartyParams + { + AuthData = new AuthData(url, login, password, token), + Corporate = isCorporate, + CustomerTitle = customerTitle, + ProviderId = providerId, + ProviderKey = providerKey, + }; + + var folder = FileStorageService.SaveThirdParty(thirdPartyParams); + + return FolderWrapperHelper.Get(folder); + } + + public IEnumerable GetThirdPartyAccounts() + { + return FileStorageService.GetThirdParty(); + } + + public object DeleteThirdParty(int providerId) + { + return FileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture)); + + } + + ///// + ///// + ///// + ///// + ///// + //[Read(@"@search/{query}")] + //public IEnumerable Search(string query) + //{ + // var searcher = new SearchHandler(); + // var files = searcher.SearchFiles(query).Select(r => (FileEntryWrapper)FileWrapperHelper.Get(r)); + // var folders = searcher.SearchFolders(query).Select(f => (FileEntryWrapper)FolderWrapperHelper.Get(f)); + + // return files.Concat(folders); + //} + + public bool StoreOriginal(bool set) + { + return FileStorageService.StoreOriginal(set); + } + + public bool HideConfirmConvert(bool save) + { + return FileStorageService.HideConfirmConvert(save); + } + + public bool UpdateIfExist(bool set) + { + return FileStorageService.UpdateIfExist(set); + } + + public IEnumerable CheckDocServiceUrl(string docServiceUrl, string docServiceUrlInternal, string docServiceUrlPortal) + { + FilesLinkUtility.DocServiceUrl = docServiceUrl; + FilesLinkUtility.DocServiceUrlInternal = docServiceUrlInternal; + FilesLinkUtility.DocServicePortalUrl = docServiceUrlPortal; + + MessageService.Send(MessageAction.DocumentServiceLocationSetting); + + var https = new Regex(@"^https://", RegexOptions.IgnoreCase); + var http = new Regex(@"^http://", RegexOptions.IgnoreCase); + if (https.IsMatch(CommonLinkUtility.GetFullAbsolutePath("")) && http.IsMatch(FilesLinkUtility.DocServiceUrl)) + { + throw new Exception("Mixed Active Content is not allowed. HTTPS address for Document Server is required."); + } + + DocumentServiceConnector.CheckDocServiceUrl(); + + return new[] + { + FilesLinkUtility.DocServiceUrl, + FilesLinkUtility.DocServiceUrlInternal, + FilesLinkUtility.DocServicePortalUrl + }; + } + + public object GetDocServiceUrl(bool version) + { + var url = CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.DocServiceApiUrl); + if (!version) + { + return url; + } + + var dsVersion = DocumentServiceConnector.GetVersion(); + + return new + { + version = dsVersion, + docServiceUrlApi = url, + }; + } + + + private FolderContentWrapper ToFolderContentWrapper(T folderId, Guid userIdOrGroupId, FilterType filterType) + { + if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) + { + sortBy = SortedByType.AZ; + } + + var startIndex = Convert.ToInt32(ApiContext.StartIndex); + return FolderContentWrapperHelper.Get(FileStorageService.GetFolderItems(folderId, + startIndex, + Convert.ToInt32(ApiContext.Count) - 1, //NOTE: in ApiContext +1 + filterType, + filterType == FilterType.ByUser, + userIdOrGroupId.ToString(), + ApiContext.FilterValue, + false, + false, + new OrderBy(sortBy, !ApiContext.SortDescending)), + startIndex); + } + + #region wordpress + + public object GetWordpressInfo() + { + var token = WordpressToken.GetToken(); + if (token != null) + { + var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken); + var blogId = JObject.Parse(meInfo).Value("token_site_id"); + var wordpressUserName = JObject.Parse(meInfo).Value("username"); + + var blogInfo = RequestHelper.PerformRequest(WordpressLoginProvider.WordpressSites + blogId, "", "GET", ""); + var jsonBlogInfo = JObject.Parse(blogInfo); + jsonBlogInfo.Add("username", wordpressUserName); + + blogInfo = jsonBlogInfo.ToString(); + return new + { + success = true, + data = blogInfo + }; + } + return new + { + success = false + }; + } + + public object DeleteWordpressInfo() + { + var token = WordpressToken.GetToken(); + if (token != null) + { + WordpressToken.DeleteToken(token); + return new + { + success = true + }; + } + return new + { + success = false + }; + } + + public object WordpressSave(string code) + { + if (code == "") + { + return new + { + success = false + }; + } + try + { + var token = OAuth20TokenHelper.GetAccessToken(ConsumerFactory, code); + WordpressToken.SaveToken(token); + var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken); + var blogId = JObject.Parse(meInfo).Value("token_site_id"); + + var wordpressUserName = JObject.Parse(meInfo).Value("username"); + + var blogInfo = RequestHelper.PerformRequest(WordpressLoginProvider.WordpressSites + blogId, "", "GET", ""); + var jsonBlogInfo = JObject.Parse(blogInfo); + jsonBlogInfo.Add("username", wordpressUserName); + + blogInfo = jsonBlogInfo.ToString(); + return new + { + success = true, + data = blogInfo + }; + } + catch (Exception) + { + return new + { + success = false + }; + } + } + + public bool CreateWordpressPost(string code, string title, string content, int status) + { + try + { + var token = WordpressToken.GetToken(); + var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken); + var parser = JObject.Parse(meInfo); + if (parser == null) return false; + var blogId = parser.Value("token_site_id"); + + if (blogId != null) + { + var createPost = WordpressHelper.CreateWordpressPost(title, content, status, blogId, token); + return createPost; + } + return false; + } + catch (Exception) + { + return false; + } + } + + #endregion + + #region easybib + + public object GetEasybibCitationList(int source, string data) + { + try + { + var citationList = EasyBibHelper.GetEasyBibCitationsList(source, data); + return new + { + success = true, + citations = citationList + }; + } + catch (Exception) + { + return new + { + success = false + }; + } + + } + + public object GetEasybibStyles() + { + try + { + var data = EasyBibHelper.GetEasyBibStyles(); + return new + { + success = true, + styles = data + }; + } + catch (Exception) + { + return new + { + success = false + }; + } + } + + public object EasyBibCitationBook(string citationData) + { + try + { + var citat = EasyBibHelper.GetEasyBibCitation(citationData); + if (citat != null) + { + return new + { + success = true, + citation = citat + }; + } + else + { + return new + { + success = false + }; + } + + } + catch (Exception) + { + return new + { + success = false + }; + } + } + + #endregion + } + + public static class FilesControllerHelperExtention + { + public static DIHelper AddFilesControllerHelperService(this DIHelper services) + { + services.TryAddScoped>(); + services.TryAddScoped>(); + + return services + .AddEasyBibHelperService() + .AddWordpressTokenService() + .AddWordpressHelperService() + .AddFolderContentWrapperHelperService() + .AddFileUploaderService() + .AddFileShareParamsService() + .AddFileShareWrapperService() + .AddFileOperationWraperHelperService() + .AddFileWrapperHelperService() + .AddFolderWrapperHelperService() + .AddConsumerFactoryService() + .AddDocumentServiceConnectorService() + .AddCommonLinkUtilityService() + .AddMessageServiceService() + .AddThirdpartyConfigurationService() + .AddCoreBaseSettingsService() + .AddWebItemSecurity() + .AddUserManagerService() + .AddEntryManagerService() + .AddTenantManagerService() + .AddSecurityContextService() + .AddDocumentServiceHelperService() + .AddFilesLinkUtilityService() + .AddApiContextService() + .AddFileStorageService() + .AddGlobalFolderHelperService() + .AddFilesSettingsHelperService() + .AddBoxLoginProviderService() + .AddDropboxLoginProviderService() + .AddOneDriveLoginProviderService() + .AddGoogleLoginProviderService() + .AddChunkedUploadSessionHelperService() + .AddProductEntryPointService() + ; + } + } +} diff --git a/products/ASC.Files/Server/Model/BatchModel.cs b/products/ASC.Files/Server/Model/BatchModel.cs index 4640f15600..af932aaaed 100644 --- a/products/ASC.Files/Server/Model/BatchModel.cs +++ b/products/ASC.Files/Server/Model/BatchModel.cs @@ -5,26 +5,28 @@ using ASC.Web.Files.Services.WCFService.FileOperations; namespace ASC.Files.Model { - public class BaseBatchModel + public class BaseBatchModel { - public IEnumerable FolderIds { get; set; } - public IEnumerable FileIds { get; set; } + public IEnumerable FolderIdsInt { get; set; } + public IEnumerable FolderIdsString { get; set; } + public IEnumerable FolderIds { get; set; } + public IEnumerable FileIds { get; set; } } - public class DownloadModel : BaseBatchModel + public class DownloadModel : BaseBatchModel { public IEnumerable> FileConvertIds { get; set; } } - public class DeleteBatchModel : BaseBatchModel + public class DeleteBatchModel : BaseBatchModel { public bool DeleteAfter { get; set; } public bool Immediately { get; set; } } - public class BatchModel : BaseBatchModel + public class BatchModel : BaseBatchModel { - public string DestFolderId { get; set; } + public T DestFolderId { get; set; } public FileConflictResolveType ConflictResolveType { get; set; } public bool DeleteAfter { get; set; } } From 50c745dbd0ed58fca82639ff03e6e11621a89d8c Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Thu, 19 Mar 2020 15:56:34 +0300 Subject: [PATCH 20/30] Files: ComposeFileOperation --- .../Server/Controllers/FilesController.cs | 66 ++----- .../Server/Core/FileStorageService.cs | 5 + .../Server/Helpers/FilesControllerHelper.cs | 4 +- products/ASC.Files/Server/Model/BatchModel.cs | 7 +- .../FileOperations/FileDeleteOperation.cs | 14 ++ .../FileOperations/FileOperation.cs | 164 +++++++++++------- .../FileOperations/FileOperationsManager.cs | 22 ++- 7 files changed, 162 insertions(+), 120 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index ec0c81d792..ff82365f3c 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -81,17 +81,11 @@ namespace ASC.Api.Documents public FilesControllerHelper FilesControllerHelperInt { get; } public FileStorageService FileStorageServiceInt { get; } public GlobalFolderHelper GlobalFolderHelper { get; } - public FileWrapperHelper FileWrapperHelper { get; } public FilesSettingsHelper FilesSettingsHelper { get; } public FilesLinkUtility FilesLinkUtility { get; } - public FileUploader FileUploader { get; } - public DocumentServiceHelper DocumentServiceHelper { get; } - public TenantManager TenantManager { get; } public SecurityContext SecurityContext { get; } public FolderWrapperHelper FolderWrapperHelper { get; } public FileOperationWraperHelper FileOperationWraperHelper { get; } - public FileShareWrapperHelper FileShareWrapperHelper { get; } - public FileShareParamsHelper FileShareParamsHelper { get; } public EntryManager EntryManager { get; } public UserManager UserManager { get; } public WebItemSecurity WebItemSecurity { get; } @@ -109,7 +103,6 @@ namespace ASC.Api.Documents public WordpressHelper WordpressHelper { get; } public ConsumerFactory ConsumerFactory { get; } public EasyBibHelper EasyBibHelper { get; } - public ChunkedUploadSessionHelper ChunkedUploadSessionHelper { get; } public ProductEntryPoint ProductEntryPoint { get; } /// @@ -123,17 +116,11 @@ namespace ASC.Api.Documents FileStorageService fileStorageService, FileStorageService fileStorageServiceInt, GlobalFolderHelper globalFolderHelper, - FileWrapperHelper fileWrapperHelper, FilesSettingsHelper filesSettingsHelper, FilesLinkUtility filesLinkUtility, - FileUploader fileUploader, - DocumentServiceHelper documentServiceHelper, - TenantManager tenantManager, SecurityContext securityContext, FolderWrapperHelper folderWrapperHelper, FileOperationWraperHelper fileOperationWraperHelper, - FileShareWrapperHelper fileShareWrapperHelper, - FileShareParamsHelper fileShareParamsHelper, EntryManager entryManager, UserManager userManager, WebItemSecurity webItemSecurity, @@ -156,17 +143,11 @@ namespace ASC.Api.Documents FileStorageService = fileStorageService; FileStorageServiceInt = fileStorageServiceInt; GlobalFolderHelper = globalFolderHelper; - FileWrapperHelper = fileWrapperHelper; FilesSettingsHelper = filesSettingsHelper; FilesLinkUtility = filesLinkUtility; - FileUploader = fileUploader; - DocumentServiceHelper = documentServiceHelper; - TenantManager = tenantManager; SecurityContext = securityContext; FolderWrapperHelper = folderWrapperHelper; FileOperationWraperHelper = fileOperationWraperHelper; - FileShareWrapperHelper = fileShareWrapperHelper; - FileShareParamsHelper = fileShareParamsHelper; EntryManager = entryManager; UserManager = userManager; WebItemSecurity = webItemSecurity; @@ -184,7 +165,6 @@ namespace ASC.Api.Documents WordpressToken = wordpressToken; WordpressHelper = wordpressHelper; EasyBibHelper = easyBibHelper; - ChunkedUploadSessionHelper = chunkedUploadSessionHelper; ProductEntryPoint = productEntryPoint; } @@ -1059,14 +1039,10 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/delete")] - public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) + public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) { - var itemList = new ItemList(); - - itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately).Select(FileOperationWraperHelper.Get); + return FileStorageService.DeleteItems("delete", batch.FileIds.ToList(), batch.FolderIds.ToList(), false, batch.DeleteAfter, batch.Immediately) + .Select(FileOperationWraperHelper.Get); } /// @@ -1076,9 +1052,9 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/emptytrash")] - public IEnumerable> EmptyTrash() + public IEnumerable> EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FilesControllerHelperInt.EmptyTrash(); } /// @@ -1240,31 +1216,13 @@ namespace ASC.Api.Documents [Update("{fileId}/sharedlink")] public string GenerateSharedLink(string fileId, FileShare share) { - var file = GetFileInfo(fileId); + return FilesControllerHelperString.GenerateSharedLink(fileId, share); + } - var objectId = "file_" + file.Id; - var sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); - if (sharedInfo == null || sharedInfo.Share != share) - { - var list = new ItemList - { - new AceWrapper - { - SubjectId = FileConstant.ShareLinkId, - SubjectGroup = true, - Share = share - } - }; - var aceCollection = new AceCollection - { - Entries = new ItemList { objectId }, - Aces = list - }; - FileStorageService.SetAceObject(aceCollection, false); - sharedInfo = FileStorageService.GetSharedInfo(new ItemList { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId); - } - - return sharedInfo.Link; + [Update("{fileId:int}/sharedlink")] + public string GenerateSharedLink(int fileId, FileShare share) + { + return FilesControllerHelperInt.GenerateSharedLink(fileId, share); } /// @@ -1384,7 +1342,7 @@ namespace ASC.Api.Documents [Read("thirdparty/common")] public IEnumerable> GetCommonThirdPartyFolders() { - var parent = FileStorageService.GetFolder(GlobalFolderHelper.FolderCommon.ToString()); + var parent = FileStorageServiceInt.GetFolder(GlobalFolderHelper.FolderCommon); return EntryManager.GetThirpartyFolders(parent); } diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 9da5437918..0b5b92dea0 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -1358,6 +1358,11 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); } + public ItemList DeleteItems(string action, List files, List folders, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) + { + return FileOperationsManagerHelper.Delete(folders, files, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); + } + public ItemList EmptyTrash() { var folderDao = GetFolderDao(); diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index 1ee2771fec..422dec2d81 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -508,9 +508,9 @@ namespace ASC.Files.Helpers .Select(FileOperationWraperHelper.Get); } - public IEnumerable> EmptyTrash() + public IEnumerable> EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } public IEnumerable> GetFileVersionInfo(T fileId) diff --git a/products/ASC.Files/Server/Model/BatchModel.cs b/products/ASC.Files/Server/Model/BatchModel.cs index af932aaaed..a3a9225141 100644 --- a/products/ASC.Files/Server/Model/BatchModel.cs +++ b/products/ASC.Files/Server/Model/BatchModel.cs @@ -7,10 +7,13 @@ namespace ASC.Files.Model { public class BaseBatchModel { - public IEnumerable FolderIdsInt { get; set; } - public IEnumerable FolderIdsString { get; set; } public IEnumerable FolderIds { get; set; } public IEnumerable FileIds { get; set; } + public BaseBatchModel() + { + FolderIds = new List(); + FileIds = new List(); + } } public class DownloadModel : BaseBatchModel diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index 2dc4518692..da6878ceb2 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using ASC.Core.Tenants; using ASC.Files.Core; @@ -55,6 +56,19 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } + class FileDeleteOperation : ComposeFileOperation, FileDeleteOperationData> + { + public FileDeleteOperation(IServiceProvider serviceProvider, FileOperation, string> f1, FileOperation, int> f2) + : base(serviceProvider, f1, f2) + { + } + + public override FileOperationType OperationType + { + get { return FileOperationType.Delete; } + } + } + class FileDeleteOperation : FileOperation, T> { private T _trashId; diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index 8047b50b0b..2cda598ecf 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -48,26 +48,7 @@ using Microsoft.Extensions.Options; namespace ASC.Web.Files.Services.WCFService.FileOperations { - abstract class FileOperationData - { - public List Folders { get; private set; } - - public List Files { get; private set; } - - public Tenant Tenant { get; } - - public bool HoldResult { get; private set; } - - protected FileOperationData(List folders, List files, Tenant tenant, bool holdResult = true) - { - Folders = folders ?? new List(); - Files = files ?? new List(); - Tenant = tenant; - HoldResult = holdResult; - } - } - - public static class FileOperation + public abstract class FileOperation { public const string SPLIT_CHAR = ":"; public const string OWNER = "Owner"; @@ -79,23 +60,107 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public const string PROCESSED = "Processed"; public const string FINISHED = "Finished"; public const string HOLD = "Hold"; - } - abstract class FileOperation where T : FileOperationData - { - private readonly IPrincipal principal; - private readonly string culture; - private int total; - private int processed; - private int successProcessed; + protected readonly IPrincipal principal; + protected readonly string culture; + protected int total; + protected int processed; + protected int successProcessed; - - protected DistributedTask TaskInfo { get; private set; } + public virtual FileOperationType OperationType { get; } + public bool HoldResult { get; set; } protected string Status { get; set; } protected string Error { get; set; } + protected DistributedTask TaskInfo { get; set; } + + public FileOperation(IServiceProvider serviceProvider) + { + principal = serviceProvider.GetService()?.HttpContext?.User ?? Thread.CurrentPrincipal; + culture = Thread.CurrentThread.CurrentCulture.Name; + + TaskInfo = new DistributedTask(); + } + + public virtual DistributedTask GetDistributedTask() + { + FillDistributedTask(); + return TaskInfo; + } + + + protected internal virtual void FillDistributedTask() + { + var progress = total != 0 ? 100 * processed / total : 0; + + TaskInfo.SetProperty(OPERATION_TYPE, OperationType); + TaskInfo.SetProperty(OWNER, ((IAccount)(principal ?? Thread.CurrentPrincipal).Identity).ID); + TaskInfo.SetProperty(PROGRESS, progress < 100 ? progress : 100); + TaskInfo.SetProperty(RESULT, Status); + TaskInfo.SetProperty(ERROR, Error); + TaskInfo.SetProperty(PROCESSED, successProcessed); + TaskInfo.SetProperty(HOLD, HoldResult); + } + + public abstract void RunJob(DistributedTask _, CancellationToken cancellationToken); + protected abstract void Do(IServiceScope serviceScope); + } + + internal class ComposeFileOperation : FileOperation + where T1 : FileOperationData + where T2 : FileOperationData + { + public FileOperation F1 { get; set; } + public FileOperation F2 { get; set; } + + public ComposeFileOperation(IServiceProvider serviceProvider, FileOperation f1, FileOperation f2) + : base(serviceProvider) + { + F1 = f1; + F2 = f2; + } + + public override void RunJob(DistributedTask _, CancellationToken cancellationToken) + { + F1.RunJob(_, cancellationToken); + F2.RunJob(_, cancellationToken); + } + + protected internal override void FillDistributedTask() + { + F1.FillDistributedTask(); + F2.FillDistributedTask(); + } + + protected override void Do(IServiceScope serviceScope) + { + throw new NotImplementedException(); + } + } + + abstract class FileOperationData + { + public List Folders { get; private set; } + + public List Files { get; private set; } + + public Tenant Tenant { get; } + + public bool HoldResult { get; set; } + + protected FileOperationData(List folders, List files, Tenant tenant, bool holdResult = true) + { + Folders = folders ?? new List(); + Files = files ?? new List(); + Tenant = tenant; + HoldResult = holdResult; + } + } + + abstract class FileOperation : FileOperation where T : FileOperationData + { protected Tenant CurrentTenant { get; private set; } protected FileSecurity FilesSecurity { get; private set; } @@ -116,17 +181,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected List Files { get; private set; } - protected bool HoldResult { get; private set; } - - public abstract FileOperationType OperationType { get; } public IServiceProvider ServiceProvider { get; } - protected FileOperation(IServiceProvider serviceProvider, T fileOperationData) + protected FileOperation(IServiceProvider serviceProvider, T fileOperationData) : base(serviceProvider) { - principal = Thread.CurrentPrincipal; - culture = Thread.CurrentThread.CurrentCulture.Name; - - TaskInfo = new DistributedTask(); ServiceProvider = serviceProvider; Files = fileOperationData.Files; Folders = fileOperationData.Folders; @@ -134,7 +192,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations CurrentTenant = fileOperationData.Tenant; } - public void RunJob(DistributedTask _, CancellationToken cancellationToken) + public override void RunJob(DistributedTask _, CancellationToken cancellationToken) { try { @@ -184,32 +242,18 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { try { - TaskInfo.SetProperty(FileOperation.FINISHED, true); + TaskInfo.SetProperty(FINISHED, true); PublishTaskInfo(); } catch { /* ignore */ } } } - public virtual DistributedTask GetDistributedTask() + protected internal override void FillDistributedTask() { - FillDistributedTask(); - return TaskInfo; - } + base.FillDistributedTask(); - - protected virtual void FillDistributedTask() - { - var progress = total != 0 ? 100 * processed / total : 0; - - TaskInfo.SetProperty(FileOperation.SOURCE, string.Join(FileOperation.SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray())); - TaskInfo.SetProperty(FileOperation.OPERATION_TYPE, OperationType); - TaskInfo.SetProperty(FileOperation.OWNER, ((IAccount)Thread.CurrentPrincipal.Identity).ID); - TaskInfo.SetProperty(FileOperation.PROGRESS, progress < 100 ? progress : 100); - TaskInfo.SetProperty(FileOperation.RESULT, Status); - TaskInfo.SetProperty(FileOperation.ERROR, Error); - TaskInfo.SetProperty(FileOperation.PROCESSED, successProcessed); - TaskInfo.SetProperty(FileOperation.HOLD, HoldResult); + TaskInfo.SetProperty(SOURCE, string.Join(SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray())); } protected virtual int InitTotalProgressSteps() @@ -235,7 +279,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations successProcessed++; if (Folders.Contains(folderId)) { - Status += string.Format("folder_{0}{1}", folderId, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", folderId, SPLIT_CHAR); return true; } return false; @@ -246,7 +290,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations successProcessed++; if (Files.Contains(fileId)) { - Status += string.Format("file_{0}{1}", fileId, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", fileId, SPLIT_CHAR); return true; } return false; @@ -257,7 +301,5 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations FillDistributedTask(); TaskInfo.PublishChanges(); } - - protected abstract void Do(IServiceScope serviceScope); } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index a2de8f9497..b70a643ba6 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -61,7 +61,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } operations = operations.Where(t => t.GetProperty(FileOperation.OWNER) == authContext.CurrentAccount.ID); - foreach (var o in operations.Where(o => DistributedTaskStatus.Running < o.Status)) + foreach (var o in operations.Where(o => o.Status > DistributedTaskStatus.Running)) { o.SetProperty(FileOperation.PROGRESS, 100); tasks.RemoveTask(o.Id); @@ -131,6 +131,21 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return QueueTask(authContext, op); } + public ItemList Delete(AuthContext authContext, TenantManager tenantManager, List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + { + var op1 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders.OfType().Select(Convert.ToInt32).ToList(), files.OfType().Select(Convert.ToInt32).ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); + var op2 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders.OfType().ToList(), files.OfType().ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); + var op = new FileDeleteOperation(ServiceProvider, op2, op1); + + return QueueTask(authContext, op); + } + + + private ItemList QueueTask(AuthContext authContext, FileOperation op) + { + tasks.QueueTask(op.RunJob, op.GetDistributedTask()); + return GetOperationResults(authContext); + } private ItemList QueueTask(AuthContext authContext, FileOperation op) where T : FileOperationData { @@ -165,6 +180,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public ItemList MoveOrCopy(List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) => FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers); + public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + { + return FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); + } + public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) => FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); } From 7862ed159db973f3cb78517bd6546fb567b43843 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Thu, 19 Mar 2020 16:18:35 +0300 Subject: [PATCH 21/30] Files: fix merge --- .../Server/Controllers/FilesController.cs | 17 +++++++++-------- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 19 +++++++++---------- .../Core/Thirdparty/ProviderAccountDao.cs | 2 +- .../Server/Helpers/FilesControllerHelper.cs | 8 ++++---- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 89962a141b..6e25a66d16 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -34,6 +34,7 @@ using System.Text.Json; using System.Text.RegularExpressions; using ASC.Api.Core; +using ASC.Api.Utils; using ASC.Common; using ASC.Core; using ASC.Core.Common.Configuration; @@ -184,7 +185,7 @@ namespace ASC.Api.Documents /// Folders /// My folder contents [Read("@my")] - public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) + public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { return ToFolderContentWrapper(GlobalFolderHelper.FolderMy, userIdOrGroupId, filterType, withsubfolders); } @@ -227,7 +228,7 @@ namespace ASC.Api.Documents /// Folders /// Shared folder contents [Read("@share")] - public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfold) + public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { return ToFolderContentWrapper(GlobalFolderHelper.FolderShare, userIdOrGroupId, filterType, withsubfolders); } @@ -243,7 +244,7 @@ namespace ASC.Api.Documents [Read("@trash")] public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { - return ToFolderContentWrapper(Convert.ToInt32(GlobalFolderHelper.FolderTrash), userIdOrGroupId, filterType, withsubfold); + return ToFolderContentWrapper(Convert.ToInt32(GlobalFolderHelper.FolderTrash), userIdOrGroupId, filterType, withsubfolders); } /// @@ -258,15 +259,15 @@ namespace ASC.Api.Documents /// Filter type /// Folder contents [Read("{folderId}", order: int.MaxValue)] - public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) + public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { - return FilesControllerHelperString.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders).NotFoundIfNull + return FilesControllerHelperString.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders).NotFoundIfNull(); } [Read("{folderId:int}", order: int.MaxValue)] - public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { - return FilesControllerHelperInt.GetFolder(folderId, userIdOrGroupId, filterType); + return FilesControllerHelperInt.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders); } /// @@ -1487,7 +1488,7 @@ namespace ASC.Api.Documents startIndex); } - private FolderContentWrapper ToFolderContentWrapper(int folderId, Guid userIdOrGroupId, FilterType filterType) + private FolderContentWrapper ToFolderContentWrapper(int folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) { diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index cfd572b828..ccc5ecd104 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -115,7 +115,6 @@ namespace ASC.Files.Core.Data public Folder GetRootFolder(int folderId) { - var folderIdString = folderId.ToString(); var id = FilesDbContext.Tree .Where(r => r.FolderId == folderId) .OrderByDescending(r => r.Level) @@ -160,8 +159,7 @@ namespace ASC.Files.Core.Data if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false); - var parentIdString = parentId.ToString(); - var q = GetFolderQuery(r => r.ParentId.ToString() == parentIdString); + var q = GetFolderQuery(r => r.ParentId == parentId); if (withSubfolders) { @@ -342,18 +340,20 @@ namespace ASC.Files.Core.Data //full path to root var oldTree = FilesDbContext.Tree - .Where(r => r.FolderId == folder.ParentFolderID) - .FirstOrDefault(); + .Where(r => r.FolderId == (int)folder.ParentFolderID); foreach (var o in oldTree) { - FolderId = folder.ID, - ParentId = oldTree.ParentId, - Level = oldTree.Level + 1 - }; + var treeToAdd = new DbFolderTree + { + FolderId = (int)folder.ID, + ParentId = o.ParentId, + Level = o.Level + 1 + }; FilesDbContext.Tree.Add(treeToAdd); } + FilesDbContext.SaveChanges(); } @@ -605,7 +605,6 @@ namespace ASC.Files.Core.Data private int GetFilesCount(int folderId) { - var folderIdString = folderId.ToString(); var count = Query(FilesDbContext.Files) .Distinct() .Where(r => FilesDbContext.Tree.Where(r => r.ParentId == folderId).Select(r => r.FolderId).Any(b => b == r.FolderId)) diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs index f06026344e..6d4000623c 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderAccountDao.cs @@ -156,7 +156,7 @@ namespace ASC.Files.Thirdparty if (!string.IsNullOrEmpty(searchText)) { - querySelect = querySelect.Where(r => BuildSearch(r, searchText, SearhTypeEnum.Any)); + querySelect = BuildSearch(querySelect, searchText, SearhTypeEnum.Any); } try diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index 422dec2d81..d1092785e2 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -150,9 +150,9 @@ namespace ASC.Files.Helpers ProductEntryPoint = productEntryPoint; } - public FolderContentWrapper GetFolder(T folderId, Guid userIdOrGroupId, FilterType filterType) + public FolderContentWrapper GetFolder(T folderId, Guid userIdOrGroupId, FilterType filterType, bool withSubFolders) { - return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull(); + return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType, withSubFolders).NotFoundIfNull(); } public List> UploadFile(T folderId, UploadModel uploadModel) @@ -766,7 +766,7 @@ namespace ASC.Files.Helpers } - private FolderContentWrapper ToFolderContentWrapper(T folderId, Guid userIdOrGroupId, FilterType filterType) + private FolderContentWrapper ToFolderContentWrapper(T folderId, Guid userIdOrGroupId, FilterType filterType, bool withSubFolders) { if (!Enum.TryParse(ApiContext.SortBy, true, out SortedByType sortBy)) { @@ -782,7 +782,7 @@ namespace ASC.Files.Helpers userIdOrGroupId.ToString(), ApiContext.FilterValue, false, - false, + withSubFolders, new OrderBy(sortBy, !ApiContext.SortDescending)), startIndex); } From e986f73293acf7dad93184aa2fd91dc08b48754f Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 20 Mar 2020 11:11:38 +0300 Subject: [PATCH 22/30] Files: fixed ComposeFileOperation --- .../ASC.Common/Threading/DistributedTask.cs | 2 +- .../FileOperations/FileOperation.cs | 92 +++++++++++++++---- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/common/ASC.Common/Threading/DistributedTask.cs b/common/ASC.Common/Threading/DistributedTask.cs index 1b75708810..fb6f5f8bcd 100644 --- a/common/ASC.Common/Threading/DistributedTask.cs +++ b/common/ASC.Common/Threading/DistributedTask.cs @@ -33,7 +33,7 @@ namespace ASC.Common.Threading { public class DistributedTask { - internal Action Publication { get; set; } + public Action Publication { get; set; } public DistributedTaskCache DistributedTaskCache { get; internal set; } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index 2cda598ecf..2b8968b796 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -63,16 +63,18 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected readonly IPrincipal principal; protected readonly string culture; - protected int total; + public int Total { get; set; } + public string Source { get; set; } + protected int processed; protected int successProcessed; public virtual FileOperationType OperationType { get; } public bool HoldResult { get; set; } - protected string Status { get; set; } + public string Status { get; set; } - protected string Error { get; set; } + public string Error { get; set; } protected DistributedTask TaskInfo { get; set; } @@ -93,7 +95,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected internal virtual void FillDistributedTask() { - var progress = total != 0 ? 100 * processed / total : 0; + var progress = Total != 0 ? 100 * processed / Total : 0; TaskInfo.SetProperty(OPERATION_TYPE, OperationType); TaskInfo.SetProperty(OWNER, ((IAccount)(principal ?? Thread.CurrentPrincipal).Identity).ID); @@ -112,26 +114,84 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations where T1 : FileOperationData where T2 : FileOperationData { - public FileOperation F1 { get; set; } - public FileOperation F2 { get; set; } + public FileOperation ThirdPartyOperation { get; set; } + public FileOperation DaoOperation { get; set; } - public ComposeFileOperation(IServiceProvider serviceProvider, FileOperation f1, FileOperation f2) + public ComposeFileOperation( + IServiceProvider serviceProvider, + FileOperation thirdPartyOperation, + FileOperation daoOperation) : base(serviceProvider) { - F1 = f1; - F2 = f2; + ThirdPartyOperation = thirdPartyOperation; + DaoOperation = daoOperation; } public override void RunJob(DistributedTask _, CancellationToken cancellationToken) { - F1.RunJob(_, cancellationToken); - F2.RunJob(_, cancellationToken); + ThirdPartyOperation.GetDistributedTask().Publication = PublishChanges; + ThirdPartyOperation.RunJob(_, cancellationToken); + + DaoOperation.GetDistributedTask().Publication = PublishChanges; + DaoOperation.RunJob(_, cancellationToken); } protected internal override void FillDistributedTask() { - F1.FillDistributedTask(); - F2.FillDistributedTask(); + ThirdPartyOperation.FillDistributedTask(); + DaoOperation.FillDistributedTask(); + + Total = ThirdPartyOperation.Total + DaoOperation.Total; + Source = string.Join(SPLIT_CHAR, ThirdPartyOperation.Source, DaoOperation.Source); + base.FillDistributedTask(); + } + + public void PublishChanges(DistributedTask task) + { + var thirdpartyTask = ThirdPartyOperation.GetDistributedTask(); + var daoTask = DaoOperation.GetDistributedTask(); + + var error1 = thirdpartyTask.GetProperty(ERROR); + var error2 = daoTask.GetProperty(ERROR); + + if (!string.IsNullOrEmpty(error1)) + { + Error = error1; + } + else if (!string.IsNullOrEmpty(error2)) + { + Error = error2; + } + + var status1 = thirdpartyTask.GetProperty(RESULT); + var status2 = daoTask.GetProperty(RESULT); + + if (!string.IsNullOrEmpty(status1)) + { + Status = status1; + } + else if (!string.IsNullOrEmpty(status2)) + { + Status = status2; + } + + var finished1 = thirdpartyTask.GetProperty(FINISHED); + var finished2 = daoTask.GetProperty(FINISHED); + + if (!string.IsNullOrEmpty(finished1)) + { + TaskInfo.SetProperty(FINISHED, finished1); + } + else if (!string.IsNullOrEmpty(finished2)) + { + TaskInfo.SetProperty(FINISHED, finished2); + } + + successProcessed = thirdpartyTask.GetProperty(PROCESSED) + daoTask.GetProperty(PROCESSED); + processed = (thirdpartyTask.GetProperty(PROGRESS) + daoTask.GetProperty(PROGRESS)) / 2; + + base.FillDistributedTask(); + TaskInfo.PublishChanges(); } protected override void Do(IServiceScope serviceScope) @@ -190,6 +250,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Folders = fileOperationData.Folders; HoldResult = fileOperationData.HoldResult; CurrentTenant = fileOperationData.Tenant; + Total = InitTotalProgressSteps(); + Source = string.Join(SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray()); } public override void RunJob(DistributedTask _, CancellationToken cancellationToken) @@ -218,8 +280,6 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Logger = logger; - total = InitTotalProgressSteps(); - Do(scope); } catch (AuthorizingException authError) @@ -253,7 +313,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { base.FillDistributedTask(); - TaskInfo.SetProperty(SOURCE, string.Join(SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray())); + TaskInfo.SetProperty(SOURCE, Source); } protected virtual int InitTotalProgressSteps() From 4dfdca6beaa548ef87c114cc805a38a2958b1d38 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 20 Mar 2020 16:05:34 +0300 Subject: [PATCH 23/30] Files: CrossDao --- .../Server/Core/Dao/Interfaces/IFileDao.cs | 3 + .../Server/Core/Dao/Interfaces/IFolderDao.cs | 2 + .../Server/Core/Dao/TeamlabDao/FileDao.cs | 26 ++- .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 30 ++- .../Server/Core/Thirdparty/Box/BoxFileDao.cs | 5 + .../Core/Thirdparty/Box/BoxFolderDao.cs | 14 +- .../Server/Core/Thirdparty/CrossDao.cs | 176 ++++++++++++++++++ .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 5 + .../Thirdparty/Dropbox/DropboxFolderDao.cs | 9 +- .../GoogleDrive/GoogleDriveFileDao.cs | 10 + .../GoogleDrive/GoogleDriveFolderDao.cs | 5 + .../Thirdparty/OneDrive/OneDriveFileDao.cs | 10 + .../Thirdparty/OneDrive/OneDriveFolderDao.cs | 9 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 176 ++++-------------- .../Thirdparty/ProviderDao/ProviderFileDao.cs | 15 +- .../ProviderDao/ProviderFolderDao.cs | 15 +- .../ProviderDao/ProviderSecutiryDao.cs | 8 +- .../Thirdparty/ProviderDao/ProviderTagDao.cs | 10 +- .../SharePoint/SharePointFileDao.cs | 10 + .../SharePoint/SharePointFolderDao.cs | 5 + .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 10 + .../Thirdparty/Sharpbox/SharpBoxFolderDao.cs | 5 + .../FileOperations/FileDeleteOperation.cs | 5 +- .../ASC.Files/Server/Utils/EntryManager.cs | 13 +- 24 files changed, 389 insertions(+), 187 deletions(-) create mode 100644 products/ASC.Files/Server/Core/Thirdparty/CrossDao.cs diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs index 78d851de0d..b5f752201d 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs @@ -197,6 +197,9 @@ namespace ASC.Files.Core /// The ID of the destination folder T MoveFile(T fileId, T toFolderId); + string MoveFile(T fileId, string toFolderId); + int MoveFile(T fileId, int toFolderId); + /// /// Copy the files in a folder /// diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs index 3c3d82d3b0..a01230a155 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs @@ -120,6 +120,8 @@ namespace ASC.Files.Core /// destination folder id /// T MoveFolder(T folderId, T toFolderId, CancellationToken? cancellationToken); + string MoveFolder(T folderId, string toFolderId, CancellationToken? cancellationToken); + int MoveFolder(T folderId, int toFolderId, CancellationToken? cancellationToken); /// /// copy folder diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index aff32b86a2..b125a1d585 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -37,7 +37,9 @@ using ASC.Core.Common.Settings; using ASC.Core.Tenants; using ASC.ElasticSearch; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; +using ASC.Files.Thirdparty.ProviderDao; using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Files.Core.Search; @@ -51,7 +53,7 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Files.Core.Data { - public class FileDao : AbstractDao, IFileDao + internal class FileDao : AbstractDao, IFileDao { private static readonly object syncRoot = new object(); public FactoryIndexer FactoryIndexer { get; } @@ -60,6 +62,8 @@ namespace ASC.Files.Core.Data public GlobalFolder GlobalFolder { get; } public IDaoFactory DaoFactory { get; } public ChunkedUploadSessionHolder ChunkedUploadSessionHolder { get; } + public ProviderFolderDao ProviderFolderDao { get; } + public CrossDao CrossDao { get; } public FileDao( FactoryIndexer factoryIndexer, @@ -79,7 +83,9 @@ namespace ASC.Files.Core.Data GlobalSpace globalSpace, GlobalFolder globalFolder, IDaoFactory daoFactory, - ChunkedUploadSessionHolder chunkedUploadSessionHolder) + ChunkedUploadSessionHolder chunkedUploadSessionHolder, + ProviderFolderDao providerFolderDao, + CrossDao crossDao) : base( dbContextManager, userManager, @@ -100,6 +106,8 @@ namespace ASC.Files.Core.Data GlobalFolder = globalFolder; DaoFactory = daoFactory; ChunkedUploadSessionHolder = chunkedUploadSessionHolder; + ProviderFolderDao = providerFolderDao; + CrossDao = crossDao; } public void InvalidateCache(int fileId) @@ -672,7 +680,6 @@ namespace ASC.Files.Core.Data { if (fileId == default) return default; - var fileIdString = fileId.ToString(); using (var tx = FilesDbContext.Database.BeginTransaction()) { var fromFolders = Query(FilesDbContext.Files) @@ -703,7 +710,6 @@ namespace ASC.Files.Core.Data RecalculateFilesCount(toFolderId); } - var toFolderIdString = toFolderId.ToString(); var parentFoldersIds = FilesDbContext.Tree .Where(r => r.FolderId == toFolderId) @@ -722,6 +728,18 @@ namespace ASC.Files.Core.Data return fileId; } + public string MoveFile(int fileId, string toFolderId) + { + var toSelector = ProviderFolderDao.GetSelector(toFolderId); + + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, r => r, + toFolderId, toSelector.GetFileDao(toFolderId), toSelector.ConvertId, + true); + + return moved.ID; + } + public File CopyFile(int fileId, int toFolderId) { var file = GetFile(fileId); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index ccc5ecd104..51511bd1c0 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -31,14 +31,15 @@ using System.Linq.Expressions; using System.Threading; using ASC.Common; -using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.EF; using ASC.Core.Common.Settings; using ASC.Core.Tenants; using ASC.ElasticSearch; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; +using ASC.Files.Thirdparty.ProviderDao; using ASC.Web.Files.Classes; using ASC.Web.Files.Core.Search; using ASC.Web.Studio.Core; @@ -46,11 +47,10 @@ using ASC.Web.Studio.UserControls.Statistics; using ASC.Web.Studio.Utility; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; namespace ASC.Files.Core.Data { - public class FolderDao : AbstractDao, IFolderDao + internal class FolderDao : AbstractDao, IFolderDao { private const string my = "my"; private const string common = "common"; @@ -60,7 +60,9 @@ namespace ASC.Files.Core.Data public FactoryIndexer FactoryIndexer { get; } public GlobalSpace GlobalSpace { get; } - public ILog Logger { get; } + public IDaoFactory DaoFactory { get; } + public ProviderFolderDao ProviderFolderDao { get; } + public CrossDao CrossDao { get; } public FolderDao( FactoryIndexer factoryIndexer, @@ -77,7 +79,9 @@ namespace ASC.Files.Core.Data AuthContext authContext, IServiceProvider serviceProvider, GlobalSpace globalSpace, - IOptionsMonitor options) + IDaoFactory daoFactory, + ProviderFolderDao providerFolderDao, + CrossDao crossDao) : base( dbContextManager, userManager, @@ -94,7 +98,9 @@ namespace ASC.Files.Core.Data { FactoryIndexer = factoryIndexer; GlobalSpace = globalSpace; - Logger = options.Get("ASC.Files"); + DaoFactory = daoFactory; + ProviderFolderDao = providerFolderDao; + CrossDao = crossDao; } public Folder GetFolder(int folderId) @@ -496,6 +502,18 @@ namespace ASC.Files.Core.Data return folderId; } + public string MoveFolder(int folderId, string toFolderId, CancellationToken? cancellationToken) + { + var toSelector = ProviderFolderDao.GetSelector(toFolderId); + + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, DaoFactory.GetFileDao(), r => r, + toFolderId, toSelector.GetFolderDao(toFolderId), toSelector.GetFileDao(toFolderId), toSelector.ConvertId, + true, cancellationToken); + + return moved.ID; + } + public Folder CopyFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { var folder = GetFolder(folderId); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs index c30b67b08b..584cebea03 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs @@ -537,6 +537,11 @@ namespace ASC.Files.Thirdparty.Box throw new NotImplementedException(); } + public int MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs index 74ebc638fe..94d6fa46f2 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs @@ -404,8 +404,18 @@ namespace ASC.Files.Thirdparty.Box public Dictionary GetBunchObjectIDs(List folderIDs) { return null; - } - + } + + public string MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + + int IFolderDao.MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/CrossDao.cs b/products/ASC.Files/Server/Core/Thirdparty/CrossDao.cs new file mode 100644 index 0000000000..ca06066657 --- /dev/null +++ b/products/ASC.Files/Server/Core/Thirdparty/CrossDao.cs @@ -0,0 +1,176 @@ +using System; +using System.Linq; +using System.Threading; + +using ASC.Files.Core.Data; +using ASC.Files.Resources; +using ASC.Web.Files.Utils; +using ASC.Web.Studio.Core; + +using Microsoft.Extensions.DependencyInjection; + +namespace ASC.Files.Core.Thirdparty +{ + internal class CrossDao + { + private IServiceProvider ServiceProvider { get; } + private SetupInfo SetupInfo { get; } + private FileConverter FileConverter { get; } + + public CrossDao( + IServiceProvider serviceProvider, + SetupInfo setupInfo, + FileConverter fileConverter) + { + ServiceProvider = serviceProvider; + SetupInfo = setupInfo; + FileConverter = fileConverter; + } + + public File PerformCrossDaoFileCopy( + TFrom fromFileId, IFileDao fromFileDao, Func fromConverter, + TTo toFolderId, IFileDao toFileDao, Func toConverter, + bool deleteSourceFile) + { + //Get File from first dao + var fromFile = fromFileDao.GetFile(fromConverter(fromFileId)); + + if (fromFile.ContentLength > SetupInfo.AvailableFileSize) + { + throw new Exception(string.Format(deleteSourceFile ? FilesCommonResource.ErrorMassage_FileSizeMove : FilesCommonResource.ErrorMassage_FileSizeCopy, + FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); + } + + var securityDao = ServiceProvider.GetService>(); + var tagDao = ServiceProvider.GetService>(); + + var fromFileShareRecords = securityDao.GetPureShareRecords(fromFile).Where(x => x.EntryType == FileEntryType.File); + var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFile).ToList(); + var fromFileLockTag = tagDao.GetTags(fromFile.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); + + var toFile = ServiceProvider.GetService>(); + + toFile.Title = fromFile.Title; + toFile.Encrypted = fromFile.Encrypted; + toFile.FolderID = toConverter(toFolderId); + + fromFile.ID = fromConverter(fromFile.ID); + + var mustConvert = !string.IsNullOrEmpty(fromFile.ConvertedType); + using (var fromFileStream = mustConvert + ? FileConverter.Exec(fromFile) + : fromFileDao.GetFileStream(fromFile)) + { + toFile.ContentLength = fromFileStream.CanSeek ? fromFileStream.Length : fromFile.ContentLength; + toFile = toFileDao.SaveFile(toFile, fromFileStream); + } + + if (deleteSourceFile) + { + if (fromFileShareRecords.Any()) + fromFileShareRecords.ToList().ForEach(x => + { + x.EntryId = toFile.ID; + securityDao.SetShare(x); + }); + + var fromFileTags = fromFileNewTags; + if (fromFileLockTag != null) fromFileTags.Add(fromFileLockTag); + + if (fromFileTags.Any()) + { + fromFileTags.ForEach(x => x.EntryId = toFile.ID); + + tagDao.SaveTags(fromFileTags); + } + + //Delete source file if needed + fromFileDao.DeleteFile(fromConverter(fromFileId)); + } + return toFile; + } + + public Folder PerformCrossDaoFolderCopy + (TFrom fromFolderId, IFolderDao fromFolderDao, IFileDao fromFileDao, Func fromConverter, + TTo toRootFolderId, IFolderDao toFolderDao, IFileDao toFileDao, Func toConverter, + bool deleteSourceFolder, CancellationToken? cancellationToken) + { + var fromFolder = fromFolderDao.GetFolder(fromConverter(fromFolderId)); + + var toFolder1 = ServiceProvider.GetService>(); + toFolder1.Title = fromFolder.Title; + toFolder1.ParentFolderID = toConverter(toRootFolderId); + + var toFolder = toFolderDao.GetFolder(fromFolder.Title, toConverter(toRootFolderId)); + var toFolderId = toFolder != null + ? toFolder.ID + : toFolderDao.SaveFolder(toFolder1); + + var foldersToCopy = fromFolderDao.GetFolders(fromConverter(fromFolderId)); + var fileIdsToCopy = fromFileDao.GetFiles(fromConverter(fromFolderId)); + Exception copyException = null; + //Copy files first + foreach (var fileId in fileIdsToCopy) + { + if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + try + { + PerformCrossDaoFileCopy(fileId, fromFileDao, fromConverter, + toFolderId, toFileDao, toConverter, + deleteSourceFolder); + } + catch (Exception ex) + { + copyException = ex; + } + } + foreach (var folder in foldersToCopy) + { + if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); + try + { + PerformCrossDaoFolderCopy(folder.ID, fromFolderDao, fromFileDao, fromConverter, + toFolderId, toFolderDao, toFileDao, toConverter, + deleteSourceFolder, cancellationToken); + } + catch (Exception ex) + { + copyException = ex; + } + } + + if (deleteSourceFolder) + { + var securityDao = ServiceProvider.GetService>(); + var fromFileShareRecords = securityDao.GetPureShareRecords(fromFolder) + .Where(x => x.EntryType == FileEntryType.Folder); + + if (fromFileShareRecords.Any()) + { + fromFileShareRecords.ToList().ForEach(x => + { + x.EntryId = toFolderId; + securityDao.SetShare(x); + }); + } + + var tagDao = ServiceProvider.GetService>(); + var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFolder).ToList(); + + if (fromFileNewTags.Any()) + { + fromFileNewTags.ForEach(x => x.EntryId = toFolderId); + + tagDao.SaveTags(fromFileNewTags); + } + + if (copyException == null) + fromFolderDao.DeleteFolder(fromConverter(fromFolderId)); + } + + if (copyException != null) throw copyException; + + return toFolderDao.GetFolder(toConverter(toFolderId)); + } + } +} diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 9a7e9c9d33..6c133e00c5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -368,6 +368,11 @@ namespace ASC.Files.Thirdparty.Dropbox ProviderInfo.CacheReset(MakeDropboxPath(toDropboxFolder)); return MakeId(dropboxFile); + } + + public int MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); } public File CopyFile(string fileId, string toFolderId) diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs index 06910a71b5..0cf54aabd0 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -402,8 +402,13 @@ namespace ASC.Files.Thirdparty.Dropbox public Dictionary GetBunchObjectIDs(List folderIDs) { return null; - } - + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 672e625d7f..ffdc6f0052 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -584,6 +584,16 @@ namespace ASC.Files.Thirdparty.GoogleDrive return null; } + public string MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + int IFileDao.MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs index eb93407286..3db958f5aa 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs @@ -395,6 +395,11 @@ namespace ASC.Files.Thirdparty.GoogleDrive return null; } + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index a740b3e915..c6054fe902 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -585,6 +585,16 @@ namespace ASC.Files.Thirdparty.OneDrive throw new NotImplementedException(); } + public string MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + int IFileDao.MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs index 5d4b23f4fb..ae5dfbbe80 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs @@ -405,8 +405,13 @@ namespace ASC.Files.Thirdparty.OneDrive public Dictionary GetBunchObjectIDs(List folderIDs) { return null; - } - + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index c83961b111..fe70787427 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -32,15 +32,13 @@ using System.Threading; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; -using ASC.Files.Resources; +using ASC.Files.Core.Thirdparty; using ASC.Files.Thirdparty.Box; using ASC.Files.Thirdparty.Dropbox; using ASC.Files.Thirdparty.GoogleDrive; using ASC.Files.Thirdparty.OneDrive; using ASC.Files.Thirdparty.SharePoint; using ASC.Files.Thirdparty.Sharpbox; -using ASC.Web.Files.Utils; -using ASC.Web.Studio.Core; using Microsoft.Extensions.DependencyInjection; @@ -54,14 +52,12 @@ namespace ASC.Files.Thirdparty.ProviderDao IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, - SetupInfo setupInfo, - FileConverter fileConverter) + CrossDao crossDao) { ServiceProvider = serviceProvider; SecurityDao = securityDao; TagDao = tagDao; - SetupInfo = setupInfo; - FileConverter = fileConverter; + CrossDao = crossDao; Selectors = new List { //Fill in selectors @@ -77,8 +73,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public IServiceProvider ServiceProvider { get; } public SecurityDao SecurityDao { get; } public TagDao TagDao { get; } - public SetupInfo SetupInfo { get; } - public FileConverter FileConverter { get; } + public CrossDao CrossDao { get; } protected bool IsCrossDao(string id1, string id2) { @@ -87,7 +82,7 @@ namespace ASC.Files.Thirdparty.ProviderDao return !Equals(GetSelector(id1).GetIdCode(id1), GetSelector(id2).GetIdCode(id2)); } - protected IDaoSelector GetSelector(string id) + public IDaoSelector GetSelector(string id) { return Selectors.FirstOrDefault(selector => selector.IsMatch(id)); } @@ -112,153 +107,47 @@ namespace ASC.Files.Thirdparty.ProviderDao } - protected File PerformCrossDaoFileCopy(string fromFileId, string toFolderId, bool deleteSourceFile) + protected internal File PerformCrossDaoFileCopy(string fromFileId, string toFolderId, bool deleteSourceFile) { var fromSelector = GetSelector(fromFileId); var toSelector = GetSelector(toFolderId); - //Get File from first dao - var fromFileDao = fromSelector.GetFileDao(fromFileId); - var toFileDao = toSelector.GetFileDao(toFolderId); - var fromFile = fromFileDao.GetFile(fromSelector.ConvertId(fromFileId)); - if (fromFile.ContentLength > SetupInfo.AvailableFileSize) - { - throw new Exception(string.Format(deleteSourceFile ? FilesCommonResource.ErrorMassage_FileSizeMove : FilesCommonResource.ErrorMassage_FileSizeCopy, - FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize))); - } + return CrossDao.PerformCrossDaoFileCopy( + fromFileId, fromSelector.GetFileDao(fromFileId), fromSelector.ConvertId, + toFolderId, toSelector.GetFileDao(toFolderId), toSelector.ConvertId, + deleteSourceFile); + } - var securityDao = SecurityDao; - var tagDao = TagDao; - - var fromFileShareRecords = securityDao.GetPureShareRecords(fromFile).Where(x => x.EntryType == FileEntryType.File); - var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFile).ToList(); - var fromFileLockTag = tagDao.GetTags(fromFile.ID, FileEntryType.File, TagType.Locked).FirstOrDefault(); - - var toFile = ServiceProvider.GetService>(); - - toFile.Title = fromFile.Title; - toFile.Encrypted = fromFile.Encrypted; - toFile.FolderID = toSelector.ConvertId(toFolderId); - - fromFile.ID = fromSelector.ConvertId(fromFile.ID); - - var mustConvert = !string.IsNullOrEmpty(fromFile.ConvertedType); - using (var fromFileStream = mustConvert - ? FileConverter.Exec(fromFile) - : fromFileDao.GetFileStream(fromFile)) - { - toFile.ContentLength = fromFileStream.CanSeek ? fromFileStream.Length : fromFile.ContentLength; - toFile = toFileDao.SaveFile(toFile, fromFileStream); - } - - if (deleteSourceFile) - { - if (fromFileShareRecords.Any()) - fromFileShareRecords.ToList().ForEach(x => - { - x.EntryId = toFile.ID; - securityDao.SetShare(x); - }); - - var fromFileTags = fromFileNewTags; - if (fromFileLockTag != null) fromFileTags.Add(fromFileLockTag); - - if (fromFileTags.Any()) - { - fromFileTags.ForEach(x => x.EntryId = toFile.ID); - - tagDao.SaveTags(fromFileTags); - } - - //Delete source file if needed - fromFileDao.DeleteFile(fromSelector.ConvertId(fromFileId)); - } - return toFile; + protected File PerformCrossDaoFileCopy(string fromFileId, int toFolderId, bool deleteSourceFile) + { + var fromSelector = GetSelector(fromFileId); + using var scope = ServiceProvider.CreateScope(); + return CrossDao.PerformCrossDaoFileCopy( + fromFileId, fromSelector.GetFileDao(fromFileId), fromSelector.ConvertId, + toFolderId, scope.ServiceProvider.GetService(), r => r, + deleteSourceFile); } protected Folder PerformCrossDaoFolderCopy(string fromFolderId, string toRootFolderId, bool deleteSourceFolder, CancellationToken? cancellationToken) { - //Things get more complicated var fromSelector = GetSelector(fromFolderId); var toSelector = GetSelector(toRootFolderId); - var fromFolderDao = fromSelector.GetFolderDao(fromFolderId); - var fromFileDao = fromSelector.GetFileDao(fromFolderId); - //Create new folder in 'to' folder - var toFolderDao = toSelector.GetFolderDao(toRootFolderId); - //Ohh - var fromFolder = fromFolderDao.GetFolder(fromSelector.ConvertId(fromFolderId)); + return CrossDao.PerformCrossDaoFolderCopy( + fromFolderId, fromSelector.GetFolderDao(fromFolderId), fromSelector.GetFileDao(fromFolderId), fromSelector.ConvertId, + toRootFolderId, toSelector.GetFolderDao(toRootFolderId), toSelector.GetFileDao(toRootFolderId), toSelector.ConvertId, + deleteSourceFolder, cancellationToken); + } - var toFolder1 = ServiceProvider.GetService>(); - toFolder1.Title = fromFolder.Title; - toFolder1.ParentFolderID = toSelector.ConvertId(toRootFolderId); + protected Folder PerformCrossDaoFolderCopy(string fromFolderId, int toRootFolderId, bool deleteSourceFolder, CancellationToken? cancellationToken) + { + var fromSelector = GetSelector(fromFolderId); + using var scope = ServiceProvider.CreateScope(); - var toFolder = toFolderDao.GetFolder(fromFolder.Title, toSelector.ConvertId(toRootFolderId)); - var toFolderId = toFolder != null - ? toFolder.ID - : toFolderDao.SaveFolder(toFolder1); - - var foldersToCopy = fromFolderDao.GetFolders(fromSelector.ConvertId(fromFolderId)); - var fileIdsToCopy = fromFileDao.GetFiles(fromSelector.ConvertId(fromFolderId)); - Exception copyException = null; - //Copy files first - foreach (var fileId in fileIdsToCopy) - { - if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); - try - { - PerformCrossDaoFileCopy(fileId, toFolderId, deleteSourceFolder); - } - catch (Exception ex) - { - copyException = ex; - } - } - foreach (var folder in foldersToCopy) - { - if (cancellationToken.HasValue) cancellationToken.Value.ThrowIfCancellationRequested(); - try - { - PerformCrossDaoFolderCopy(folder.ID, toFolderId, deleteSourceFolder, cancellationToken); - } - catch (Exception ex) - { - copyException = ex; - } - } - - if (deleteSourceFolder) - { - var securityDao = SecurityDao; - var fromFileShareRecords = securityDao.GetPureShareRecords(fromFolder) - .Where(x => x.EntryType == FileEntryType.Folder); - - if (fromFileShareRecords.Any()) - { - fromFileShareRecords.ToList().ForEach(x => - { - x.EntryId = toFolderId; - securityDao.SetShare(x); - }); - } - - var tagDao = TagDao; - var fromFileNewTags = tagDao.GetNewTags(Guid.Empty, fromFolder).ToList(); - - if (fromFileNewTags.Any()) - { - fromFileNewTags.ForEach(x => x.EntryId = toFolderId); - - tagDao.SaveTags(fromFileNewTags); - } - - if (copyException == null) - fromFolderDao.DeleteFolder(fromSelector.ConvertId(fromFolderId)); - } - - if (copyException != null) throw copyException; - - return toFolderDao.GetFolder(toSelector.ConvertId(toFolderId)); + return CrossDao.PerformCrossDaoFolderCopy( + fromFolderId, fromSelector.GetFolderDao(fromFolderId), fromSelector.GetFileDao(fromFolderId), fromSelector.ConvertId, + toRootFolderId, scope.ServiceProvider.GetService(), scope.ServiceProvider.GetService(), r => r, + deleteSourceFolder, cancellationToken); } public void Dispose() @@ -271,6 +160,7 @@ namespace ASC.Files.Thirdparty.ProviderDao { public static DIHelper AddProviderDaoBaseService(this DIHelper services) { + services.TryAddScoped(); return services .AddSharpBoxDaoSelectorService() .AddSharePointSelectorService() diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index d03fcef4b5..d7b7642ab6 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -32,9 +32,8 @@ using System.Linq; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; +using ASC.Files.Core.Thirdparty; using ASC.Web.Files.Services.DocumentService; -using ASC.Web.Files.Utils; -using ASC.Web.Studio.Core; namespace ASC.Files.Thirdparty.ProviderDao { @@ -44,9 +43,8 @@ namespace ASC.Files.Thirdparty.ProviderDao IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, - SetupInfo setupInfo, - FileConverter fileConverter) - : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + CrossDao crossDao) + : base(serviceProvider, securityDao, tagDao, crossDao) { } @@ -468,6 +466,12 @@ namespace ASC.Files.Thirdparty.ProviderDao throw new NotImplementedException(); } + public int MoveFile(string fileId, int toFolderId) + { + var movedFile = PerformCrossDaoFileCopy(fileId, toFolderId, true); + return movedFile.ID; + } + #endregion } @@ -476,6 +480,7 @@ namespace ASC.Files.Thirdparty.ProviderDao public static DIHelper AddProviderFileDaoService(this DIHelper services) { services.TryAddScoped, ProviderFileDao>(); + services.TryAddScoped(); services.TryAddScoped>(); return services diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs index 5ffb6d35c9..711a69590e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs @@ -32,8 +32,7 @@ using System.Threading; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; -using ASC.Web.Files.Utils; -using ASC.Web.Studio.Core; +using ASC.Files.Core.Thirdparty; namespace ASC.Files.Thirdparty.ProviderDao { @@ -43,9 +42,8 @@ namespace ASC.Files.Thirdparty.ProviderDao IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, - SetupInfo setupInfo, - FileConverter fileConverter) - : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + CrossDao crossDao) + : base(serviceProvider, securityDao, tagDao, crossDao) { } @@ -186,6 +184,12 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); return folderDao.MoveFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null); } + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var newFolder = PerformCrossDaoFolderCopy(folderId, toFolderId, true, cancellationToken); + return newFolder.ID; + } + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var selector = GetSelector(folderId); @@ -348,6 +352,7 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); public static DIHelper AddProviderFolderDaoService(this DIHelper services) { services.TryAddScoped, ProviderFolderDao>(); + services.TryAddScoped(); services.TryAddScoped>(); return services diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs index b060d3cb18..4f3e76cf73 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs @@ -32,8 +32,7 @@ using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Security; -using ASC.Web.Files.Utils; -using ASC.Web.Studio.Core; +using ASC.Files.Core.Thirdparty; using Microsoft.Extensions.DependencyInjection; @@ -44,9 +43,8 @@ namespace ASC.Files.Thirdparty.ProviderDao public ProviderSecurityDao(IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, - SetupInfo setupInfo, - FileConverter fileConverter) - : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + CrossDao crossDao) + : base(serviceProvider, securityDao, tagDao, crossDao) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs index 659f85bda6..3ad987e620 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs @@ -30,14 +30,18 @@ using System.Collections.Generic; using ASC.Common; using ASC.Files.Core; using ASC.Files.Core.Data; -using ASC.Web.Files.Utils; -using ASC.Web.Studio.Core; +using ASC.Files.Core.Thirdparty; namespace ASC.Files.Thirdparty.ProviderDao { internal class ProviderTagDao : ProviderDaoBase, ITagDao { - public ProviderTagDao(IServiceProvider serviceProvider, SecurityDao securityDao, TagDao tagDao, SetupInfo setupInfo, FileConverter fileConverter) : base(serviceProvider, securityDao, tagDao, setupInfo, fileConverter) + public ProviderTagDao( + IServiceProvider serviceProvider, + SecurityDao securityDao, + TagDao tagDao, + CrossDao crossDao) + : base(serviceProvider, securityDao, tagDao, crossDao) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 627f1b4e41..6983c6fbb9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -414,6 +414,16 @@ namespace ASC.Files.Thirdparty.SharePoint throw new NotImplementedException(); } + public string MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + int IFileDao.MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs index 5bb509e703..3aed0f7865 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs @@ -363,6 +363,11 @@ namespace ASC.Files.Thirdparty.SharePoint return null; } + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 25eb8e4808..c76d070de6 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -640,6 +640,16 @@ namespace ASC.Files.Thirdparty.Sharpbox throw new NotImplementedException(); } + public string MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + + int IFileDao.MoveFile(string fileId, int toFolderId) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs index 205721380d..452b0924eb 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs @@ -426,6 +426,11 @@ namespace ASC.Files.Thirdparty.Sharpbox return null; } + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + throw new NotImplementedException(); + } + #endregion } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index da6878ceb2..190b1da07b 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -71,7 +71,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations class FileDeleteOperation : FileOperation, T> { - private T _trashId; + private int _trashId; private readonly bool _ignoreException; private readonly bool _immediately; private readonly Dictionary _headers; @@ -93,7 +93,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected override void Do(IServiceScope scope) { - _trashId = FolderDao.GetFolderIDTrash(true); + var folderDao = scope.ServiceProvider.GetService>(); + _trashId = folderDao.GetFolderIDTrash(true); Folder root = null; if (0 < Folders.Count) diff --git a/products/ASC.Files/Server/Utils/EntryManager.cs b/products/ASC.Files/Server/Utils/EntryManager.cs index 3c5853a591..dace1fda7b 100644 --- a/products/ASC.Files/Server/Utils/EntryManager.cs +++ b/products/ASC.Files/Server/Utils/EntryManager.cs @@ -1028,14 +1028,11 @@ namespace ASC.Web.Files.Utils } } - var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true); - foreach (var file - in files.Where(file => - file.Shared - && fileSecurity.GetShares(file) - .Any(record => - record.Subject != FileConstant.ShareLinkId - && record.Share != FileShare.Restrict))) + var files = fileDao.GetFiles(parentId, null, FilterType.None, false, Guid.Empty, string.Empty, true) + .Where(file => file.Shared && + fileSecurity.GetShares(file).Any(record => record.Subject != FileConstant.ShareLinkId && record.Share != FileShare.Restrict)); + + foreach (var file in files) { Logger.InfoFormat("Move shared file {0} from {1} to {2}", file.ID, parentId, toId); fileDao.MoveFile(file.ID, toId); From 4eab409bef36b9bcf63a7b78afa5bb03a127164d Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 20 Mar 2020 17:35:51 +0300 Subject: [PATCH 24/30] Files: delete operation --- .../Server/Controllers/FilesController.cs | 1 - .../Server/Core/Dao/TeamlabDao/FileDao.cs | 6 +-- .../Server/Core/FileStorageService.cs | 10 ++-- .../Server/Helpers/FilesControllerHelper.cs | 31 ++--------- .../FileOperations/FileOperation.cs | 1 + .../FileOperations/FileOperationsManager.cs | 54 ++++++++++++++----- 6 files changed, 55 insertions(+), 48 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 6e25a66d16..6e76cc2460 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -135,7 +135,6 @@ namespace ASC.Api.Documents WordpressHelper wordpressHelper, ConsumerFactory consumerFactory, EasyBibHelper easyBibHelper, - ChunkedUploadSessionHelper chunkedUploadSessionHelper, ProductEntryPoint productEntryPoint) { ApiContext = context; diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index b125a1d585..3be38b8975 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -684,13 +684,13 @@ namespace ASC.Files.Core.Data { var fromFolders = Query(FilesDbContext.Files) .Where(r => r.Id == fileId) - .GroupBy(r => r.Id) - .SelectMany(r => r.Select(a => a.FolderId)) + .Select(a => a.FolderId) .Distinct() .ToList(); var toUpdate = Query(FilesDbContext.Files) - .Where(r => r.Id == fileId); + .Where(r => r.Id == fileId) + .ToList(); foreach (var f in toUpdate) { diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 0b5b92dea0..258cbfcdda 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -1351,11 +1351,13 @@ namespace ASC.Web.Files.Services.WCFService return result; } - public ItemList DeleteItems(string action, ItemList items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) + public ItemList DeleteFile(string action, T fileId, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) { - ParseArrayItems(items, out var foldersId, out var filesId); - - return FileOperationsManagerHelper.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); + return FileOperationsManagerHelper.DeleteFile(fileId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); + } + public ItemList DeleteFolder(string action, T folderId, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) + { + return FileOperationsManagerHelper.DeleteFolder(folderId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); } public ItemList DeleteItems(string action, List files, List folders, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index d1092785e2..5ddef80482 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -367,14 +367,8 @@ namespace ASC.Files.Helpers public IEnumerable> DeleteFile(T fileId, bool deleteAfter, bool immediately) { - var model = new DeleteBatchModel - { - FileIds = new List { fileId }, - DeleteAfter = deleteAfter, - Immediately = immediately - }; - - return DeleteBatchItems(model); + return FileStorageService.DeleteFile("delete", fileId, false, deleteAfter, immediately) + .Select(FileOperationWraperHelper.Get); } public IEnumerable> StartConversion(T fileId) @@ -410,14 +404,8 @@ namespace ASC.Files.Helpers public IEnumerable> DeleteFolder(T folderId, bool deleteAfter, bool immediately) { - var model = new DeleteBatchModel - { - FolderIds = new List { folderId }, - DeleteAfter = deleteAfter, - Immediately = immediately - }; - - return DeleteBatchItems(model); + return FileStorageService.DeleteFile("delete", folderId, false, deleteAfter, immediately) + .Select(FileOperationWraperHelper.Get); } public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) @@ -497,17 +485,6 @@ namespace ASC.Files.Helpers return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); } - public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) - { - var itemList = new ItemList(); - - itemList.AddRange((batch.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batch.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.DeleteItems("delete", itemList, false, batch.DeleteAfter, batch.Immediately) - .Select(FileOperationWraperHelper.Get); - } - public IEnumerable> EmptyTrash() { return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index 2b8968b796..b0979f83e6 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -141,6 +141,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations ThirdPartyOperation.FillDistributedTask(); DaoOperation.FillDistributedTask(); + HoldResult = ThirdPartyOperation.HoldResult || DaoOperation.HoldResult; Total = ThirdPartyOperation.Total + DaoOperation.Total; Source = string.Join(SPLIT_CHAR, ThirdPartyOperation.Source, DaoOperation.Source); base.FillDistributedTask(); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index b70a643ba6..2522b0d0fb 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -79,7 +79,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Result = o.GetProperty(FileOperation.RESULT), Error = o.GetProperty(FileOperation.ERROR), Finished = o.GetProperty(FileOperation.FINISHED), - }); + }) + .ToList(); return new ItemList(results); } @@ -170,23 +171,50 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations TenantManager = tenantManager; } - public ItemList GetOperationResults() => FileOperationsManager.GetOperationResults(AuthContext); - public ItemList CancelOperations() => FileOperationsManager.CancelOperations(AuthContext); - public ItemList MarkAsRead(List folderIds, List fileIds) - => FileOperationsManager.MarkAsRead(AuthContext, TenantManager, folderIds, fileIds); - public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) - => FileOperationsManager.Download(AuthContext, TenantManager, folders, files, headers); - - public ItemList MoveOrCopy(List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) - => FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers); - + public ItemList GetOperationResults() + { + return FileOperationsManager.GetOperationResults(AuthContext); + } + + public ItemList CancelOperations() + { + return FileOperationsManager.CancelOperations(AuthContext); + } + + public ItemList MarkAsRead(List folderIds, List fileIds) + { + return FileOperationsManager.MarkAsRead(AuthContext, TenantManager, folderIds, fileIds); + } + + public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) + { + return FileOperationsManager.Download(AuthContext, TenantManager, folders, files, headers); + } + + public ItemList MoveOrCopy(List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) + { + return FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers); + } + public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) { return FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); } - public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) - => FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); + public ItemList Delete(List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + { + return FileOperationsManager.Delete(AuthContext, TenantManager, folders, files, ignoreException, holdResult, immediately, headers); + } + + public ItemList DeleteFile(T file, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + { + return Delete(new List(), new List() { file }, ignoreException, holdResult, immediately, headers); + } + + public ItemList DeleteFolder(T folder, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + { + return Delete(new List() { folder }, new List(), ignoreException, holdResult, immediately, headers); + } } public static class FileOperationsManagerHelperExtention From 22e379b37b2c179153b4fe8713907777e4c44a07 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Tue, 24 Mar 2020 15:30:16 +0300 Subject: [PATCH 25/30] Files: MoveOrCopy operation --- common/ASC.MessagingSystem/MessageTarget.cs | 16 ++ .../Server/Controllers/FilesController.cs | 57 ++--- .../Server/Core/Dao/Interfaces/IFileDao.cs | 5 +- .../Server/Core/Dao/Interfaces/IFolderDao.cs | 10 + .../Server/Core/Dao/TeamlabDao/FileDao.cs | 42 ++++ .../Server/Core/Dao/TeamlabDao/FolderDao.cs | 75 +++++++ .../Server/Core/FileStorageService.cs | 90 +++++--- .../Server/Core/Thirdparty/Box/BoxDaoBase.cs | 10 +- .../Server/Core/Thirdparty/Box/BoxFileDao.cs | 78 ++++++- .../Core/Thirdparty/Box/BoxFolderDao.cs | 126 +++++++++-- .../Core/Thirdparty/Box/BoxProviderInfo.cs | 6 +- .../Thirdparty/CachedProviderAccountDao.cs | 12 +- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 73 ++++++- .../Thirdparty/Dropbox/DropboxFolderDao.cs | 112 +++++++++- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 1 + .../GoogleDrive/GoogleDriveFileDao.cs | 84 ++++++-- .../GoogleDrive/GoogleDriveFolderDao.cs | 111 +++++++++- .../GoogleDrive/GoogleDriveProviderInfo.cs | 1 + .../Core/Thirdparty/IThirdPartyProviderDao.cs | 1 + .../Thirdparty/OneDrive/OneDriveFileDao.cs | 86 ++++++-- .../Thirdparty/OneDrive/OneDriveFolderDao.cs | 116 ++++++++++- .../OneDrive/OneDriveProviderInfo.cs | 4 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 13 +- .../Thirdparty/ProviderDao/ProviderFileDao.cs | 51 ++++- .../ProviderDao/ProviderFolderDao.cs | 69 +++++- .../ProviderDao/ProviderSecutiryDao.cs | 7 +- .../Thirdparty/ProviderDao/ProviderTagDao.cs | 4 +- .../Core/Thirdparty/RegexDaoSelectorBase.cs | 5 +- .../SharePoint/SharePointFileDao.cs | 82 +++++++- .../SharePoint/SharePointFolderDao.cs | 110 +++++++++- .../SharePoint/SharePointProviderInfo.cs | 7 +- .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 84 ++++++-- .../Thirdparty/Sharpbox/SharpBoxFolderDao.cs | 111 +++++++++- .../Sharpbox/SharpBoxProviderInfo.cs | 4 +- .../Server/Helpers/FilesControllerHelper.cs | 75 +++---- .../Server/Helpers/FilesMessageService.cs | 4 +- products/ASC.Files/Server/Model/BatchModel.cs | 4 +- .../Server/Model/FileOperationWraper.cs | 78 +++++-- .../FileOperations/FileDeleteOperation.cs | 12 +- .../FileOperations/FileDownloadOperation.cs | 2 +- .../FileOperations/FileMarkAsReadOperation.cs | 2 +- .../FileOperations/FileMoveCopyOperation.cs | 197 +++++++++++++----- .../FileOperations/FileOperation.cs | 32 ++- .../FileOperations/FileOperationsManager.cs | 22 +- .../ASC.Files/Server/ThirdPartyApp/Token.cs | 2 +- 45 files changed, 1754 insertions(+), 339 deletions(-) diff --git a/common/ASC.MessagingSystem/MessageTarget.cs b/common/ASC.MessagingSystem/MessageTarget.cs index 76306526ef..cb6da8a2aa 100644 --- a/common/ASC.MessagingSystem/MessageTarget.cs +++ b/common/ASC.MessagingSystem/MessageTarget.cs @@ -74,6 +74,22 @@ namespace ASC.MessagingSystem return null; } + } + + public MessageTarget Create(IEnumerable value) + { + try + { + return new MessageTarget(Option) + { + _items = value.Distinct() + }; + } + catch (Exception e) + { + Log.Error("EventMessageTarget exception", e); + return null; + } } public MessageTarget Parse(string value) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 6e76cc2460..939e3eb185 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -822,13 +822,13 @@ namespace ASC.Api.Documents /// Don't move to the Recycle Bin /// Operation result [Delete("file/{fileId}")] - public IEnumerable> DeleteFile(string fileId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFile(string fileId, bool deleteAfter, bool immediately) { return FilesControllerHelperString.DeleteFile(fileId, deleteAfter, immediately); } [Delete("file/{fileId:int}")] - public IEnumerable> DeleteFile(int fileId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFile(int fileId, bool deleteAfter, bool immediately) { return FilesControllerHelperInt.DeleteFile(fileId, deleteAfter, immediately); } @@ -882,13 +882,13 @@ namespace ASC.Api.Documents /// Don't move to the Recycle Bin /// Operation result [Delete("folder/{folderId}")] - public IEnumerable> DeleteFolder(string folderId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFolder(string folderId, bool deleteAfter, bool immediately) { return FilesControllerHelperString.DeleteFolder(folderId, deleteAfter, immediately); } [Delete("folder/{folderId:int}")] - public IEnumerable> DeleteFolder(int folderId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFolder(int folderId, bool deleteAfter, bool immediately) { return FilesControllerHelperInt.DeleteFolder(folderId, deleteAfter, immediately); } @@ -902,18 +902,11 @@ namespace ASC.Api.Documents /// File ID list /// Conflicts file ids [Read("fileops/move")] - public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) + public IEnumerable MoveOrCopyBatchCheck(BatchModel batchModel) { return FilesControllerHelperString.MoveOrCopyBatchCheck(batchModel); } - [Read("fileops/move")] - [BodySpecific] - public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) - { - return FilesControllerHelperInt.MoveOrCopyBatchCheck(batchModel); - } - /// /// Moves all the selected files and folders to the folder with the ID specified in the request /// @@ -926,18 +919,11 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/move")] - public IEnumerable> MoveBatchItems(BatchModel batchModel) + public IEnumerable MoveBatchItems(BatchModel batchModel) { return FilesControllerHelperString.MoveBatchItems(batchModel); } - [Update("fileops/move")] - [BodySpecific] - public IEnumerable> MoveBatchItems(BatchModel batchModel) - { - return FilesControllerHelperInt.MoveBatchItems(batchModel); - } - /// /// Copies all the selected files and folders to the folder with the ID specified in the request /// @@ -950,18 +936,11 @@ namespace ASC.Api.Documents /// Delete after finished /// Operation result [Update("fileops/copy")] - public IEnumerable> CopyBatchItems(BatchModel batchModel) + public IEnumerable CopyBatchItems(BatchModel batchModel) { return FilesControllerHelperString.CopyBatchItems(batchModel); } - [BodySpecific] - [Update("fileops/copy")] - public IEnumerable> CopyBatchItems(BatchModel batchModel) - { - return FilesControllerHelperInt.CopyBatchItems(batchModel); - } - /// /// Marks all files and folders as read /// @@ -969,14 +948,14 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/markasread")] - public IEnumerable> MarkAsRead(BaseBatchModel model) + public IEnumerable MarkAsRead(BaseBatchModel model) { return FilesControllerHelperString.MarkAsRead(model); } [Update("fileops/markasread")] [BodySpecific] - public IEnumerable> MarkAsRead(BaseBatchModel model) + public IEnumerable MarkAsRead(BaseBatchModel model) { return FilesControllerHelperInt.MarkAsRead(model); } @@ -988,9 +967,9 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/terminate")] - public IEnumerable> TerminateTasks() + public IEnumerable TerminateTasks() { - return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); + return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); } @@ -1001,9 +980,9 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Read("fileops")] - public IEnumerable> GetOperationStatuses() + public IEnumerable GetOperationStatuses() { - return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); + return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); } /// @@ -1016,14 +995,14 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/bulkdownload")] - public IEnumerable> BulkDownload(DownloadModel model) + public IEnumerable BulkDownload(DownloadModel model) { return FilesControllerHelperString.BulkDownload(model); } [BodySpecific] [Update("fileops/bulkdownload")] - public IEnumerable> BulkDownload(DownloadModel model) + public IEnumerable BulkDownload(DownloadModel model) { return FilesControllerHelperInt.BulkDownload(model); } @@ -1039,10 +1018,10 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/delete")] - public IEnumerable> DeleteBatchItems(DeleteBatchModel batch) + public IEnumerable DeleteBatchItems(DeleteBatchModel batch) { return FileStorageService.DeleteItems("delete", batch.FileIds.ToList(), batch.FolderIds.ToList(), false, batch.DeleteAfter, batch.Immediately) - .Select(FileOperationWraperHelper.Get); + .Select(FileOperationWraperHelper.Get); } /// @@ -1052,7 +1031,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/emptytrash")] - public IEnumerable> EmptyTrash() + public IEnumerable EmptyTrash() { return FilesControllerHelperInt.EmptyTrash(); } diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs index b5f752201d..9af09f3e2e 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFileDao.cs @@ -196,7 +196,7 @@ namespace ASC.Files.Core /// file id /// The ID of the destination folder T MoveFile(T fileId, T toFolderId); - + TTo MoveFile(T fileId, TTo toFolderId); string MoveFile(T fileId, string toFolderId); int MoveFile(T fileId, int toFolderId); @@ -206,6 +206,9 @@ namespace ASC.Files.Core /// file id /// The ID of the destination folder File CopyFile(T fileId, T toFolderId); + File CopyFile(T fileId, TTo toFolderId); + File CopyFile(T fileId, string toFolderId); + File CopyFile(T fileId, int toFolderId); /// /// Rename file diff --git a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs index a01230a155..031f590339 100644 --- a/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/Interfaces/IFolderDao.cs @@ -120,6 +120,7 @@ namespace ASC.Files.Core /// destination folder id /// T MoveFolder(T folderId, T toFolderId, CancellationToken? cancellationToken); + TTo MoveFolder(T folderId, TTo toFolderId, CancellationToken? cancellationToken); string MoveFolder(T folderId, string toFolderId, CancellationToken? cancellationToken); int MoveFolder(T folderId, int toFolderId, CancellationToken? cancellationToken); @@ -132,6 +133,9 @@ namespace ASC.Files.Core /// /// Folder CopyFolder(T folderId, T toFolderId, CancellationToken? cancellationToken); + Folder CopyFolder(T folderId, TTo toFolderId, CancellationToken? cancellationToken); + Folder CopyFolder(T folderId, string toFolderId, CancellationToken? cancellationToken); + Folder CopyFolder(T folderId, int toFolderId, CancellationToken? cancellationToken); /// /// Validate the transfer operation directory to another directory. @@ -142,6 +146,9 @@ namespace ASC.Files.Core /// Returns pair of file ID, file name, in which the same name. /// IDictionary CanMoveOrCopy(T[] folderIds, T to); + IDictionary CanMoveOrCopy(T[] folderIds, TTo to); + IDictionary CanMoveOrCopy(T[] folderIds, string to); + IDictionary CanMoveOrCopy(T[] folderIds, int to); /// /// Rename folder @@ -178,6 +185,9 @@ namespace ASC.Files.Core /// /// bool UseRecursiveOperation(T folderId, T toRootFolderId); + bool UseRecursiveOperation(T folderId, TTo toRootFolderId); + bool UseRecursiveOperation(T folderId, string toRootFolderId); + bool UseRecursiveOperation(T folderId, int toRootFolderId); /// /// Check the possibility to calculate the number of subitems diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs index 3be38b8975..9e6c070831 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FileDao.cs @@ -676,6 +676,21 @@ namespace ASC.Files.Core.Data .Any(); } + public TTo MoveFile(int fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + public int MoveFile(int fileId, int toFolderId) { if (fileId == default) return default; @@ -740,6 +755,21 @@ namespace ASC.Files.Core.Data return moved.ID; } + public File CopyFile(int fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + public File CopyFile(int fileId, int toFolderId) { var file = GetFile(fileId); @@ -764,6 +794,18 @@ namespace ASC.Files.Core.Data return null; } + public File CopyFile(int fileId, string toFolderId) + { + var toSelector = ProviderFolderDao.GetSelector(toFolderId); + + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, r => r, + toFolderId, toSelector.GetFileDao(toFolderId), toSelector.ConvertId, + false); + + return moved; + } + public int FileRename(File file, string newTitle) { var fileIdString = file.ID.ToString(); diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index 51511bd1c0..a1ac76500a 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -438,6 +438,21 @@ namespace ASC.Files.Core.Data FactoryIndexer.DeleteAsync(new FoldersWrapper { Id = id }); } + public TTo MoveFolder(int folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + public int MoveFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { using (var tx = FilesDbContext.Database.BeginTransaction()) @@ -514,6 +529,22 @@ namespace ASC.Files.Core.Data return moved.ID; } + + public Folder CopyFolder(int folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + public Folder CopyFolder(int folderId, int toFolderId, CancellationToken? cancellationToken) { var folder = GetFolder(folderId); @@ -537,6 +568,38 @@ namespace ASC.Files.Core.Data return copy; } + public Folder CopyFolder(int folderId, string toFolderId, CancellationToken? cancellationToken) + { + var toSelector = ProviderFolderDao.GetSelector(toFolderId); + + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, DaoFactory.GetFileDao(), r => r, + toFolderId, toSelector.GetFolderDao(toFolderId), toSelector.GetFileDao(toFolderId), toSelector.ConvertId, + false, cancellationToken); + + return moved; + } + + public IDictionary CanMoveOrCopy(int[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + + public IDictionary CanMoveOrCopy(int[] folderIds, string to) + { + return new Dictionary(); + } + public IDictionary CanMoveOrCopy(int[] folderIds, int to) { var result = new Dictionary(); @@ -641,11 +704,21 @@ namespace ASC.Files.Core.Data return folder.RootFolderType != FolderType.TRASH && folder.FolderType != FolderType.BUNCH; } + public bool UseRecursiveOperation(int folderId, string toRootFolderId) + { + return true; + } + public bool UseRecursiveOperation(int folderId, int toRootFolderId) { return true; } + public bool UseRecursiveOperation(int folderId, TTo toRootFolderId) + { + return true; + } + public bool CanCalculateSubitems(int entryId) { return true; @@ -1049,6 +1122,8 @@ namespace ASC.Files.Core.Data //} //return projectTitle; } + + } public class DbFolderQuery diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 258cbfcdda..6c24c73a1d 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -323,16 +323,14 @@ namespace ASC.Web.Files.Services.WCFService return response; } - public ItemList> GetItems(ItemList items, FilterType filter, bool subjectGroup, string subjectID, string search) + public ItemList GetItems(IEnumerable filesId, IEnumerable foldersId, FilterType filter, bool subjectGroup, string subjectID, string search) { - ParseArrayItems(items, out var foldersId, out var filesId); - var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID); - var entries = Enumerable.Empty>(); + var entries = Enumerable.Empty>(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + var folderDao = DaoFactory.GetFolderDao(); + var fileDao = DaoFactory.GetFileDao(); var folders = folderDao.GetFolders(foldersId.ToArray()); folders = FileSecurity.FilterRead(folders).ToList(); entries = entries.Concat(folders); @@ -345,29 +343,29 @@ namespace ASC.Web.Files.Services.WCFService foreach (var fileEntry in entries) { - if (fileEntry is File file) + if (fileEntry is File file) { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) && !FileSecurity.CanRead(folderDao.GetFolder(file.FolderIdDisplay))) { - file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + file.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } - else if (fileEntry is Folder folder) + else if (fileEntry is Folder folder) { if (fileEntry.RootFolderType == FolderType.USER && !Equals(fileEntry.RootFolderCreator, AuthContext.CurrentAccount.ID) && !FileSecurity.CanRead(folderDao.GetFolder(folder.FolderIdDisplay))) { - folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); + folder.FolderIdDisplay = GlobalFolderHelper.GetFolderShare(); } } } - EntryManager.SetFileStatus(entries.OfType>().Where(r => r.ID != null).ToList()); + EntryManager.SetFileStatus(entries.OfType>().Where(r => r.ID != null).ToList()); - return new ItemList>(entries); + return new ItemList(entries); } public Folder CreateNewFolder(T parentId, string title) @@ -1272,22 +1270,50 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.Download(folders, files, GetHttpHeaders()); } - public ItemDictionary MoveOrCopyFilesCheck(ItemList items, T destFolderId) + + public void MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, T1 destFolderId, + out List checkedFiles, out List checkedFolders) { - if (items.Count == 0) return new ItemDictionary(); + checkedFiles = new List(); + checkedFolders = new List(); - ParseArrayItems(items, out var foldersId, out var filesId); + MoveOrCopyFilesCheck(filesId.OfType().Select(Convert.ToInt32), foldersId.OfType().Select(Convert.ToInt32), destFolderId, + out var filesInts, out var folderInts); - return new ItemDictionary(MoveOrCopyFilesCheck(filesId, foldersId, destFolderId)); + foreach (var i in filesInts) + { + checkedFiles.Add(i); + } + + foreach (var i in folderInts) + { + checkedFolders.Add(i); + } + + MoveOrCopyFilesCheck(filesId.OfType(), foldersId.OfType(), destFolderId, + out var filesStrings, out var folderStrings); + + foreach (var i in filesStrings) + { + checkedFiles.Add(i); + } + + foreach (var i in folderStrings) + { + checkedFolders.Add(i); + } } - private Dictionary MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, T destFolderId) + private void MoveOrCopyFilesCheck(IEnumerable filesId, IEnumerable foldersId, TTo destFolderId, + out List checkedFiles, out List checkedFolders) { - var result = new Dictionary(); - var folderDao = GetFolderDao(); - var fileDao = GetFileDao(); + checkedFiles = new List(); + checkedFolders = new List(); + var folderDao = DaoFactory.GetFolderDao(); + var fileDao = DaoFactory.GetFileDao(); + var destFolderDao = DaoFactory.GetFolderDao(); - var toFolder = folderDao.GetFolder(destFolderId); + var toFolder = destFolderDao.GetFolder(destFolderId); ErrorIf(toFolder == null, FilesCommonResource.ErrorMassage_FolderNotFound); ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create); @@ -1296,7 +1322,7 @@ namespace ASC.Web.Files.Services.WCFService var file = fileDao.GetFile(id); if (file != null && fileDao.IsExist(file.Title, toFolder.ID)) { - result.Add(id.ToString(), file.Title); + checkedFiles.Add(id); } } @@ -1304,7 +1330,7 @@ namespace ASC.Web.Files.Services.WCFService var foldersProject = folders.Where(folder => folder.FolderType == FolderType.BUNCH).ToList(); if (foldersProject.Any()) { - var toSubfolders = folderDao.GetFolders(toFolder.ID); + var toSubfolders = destFolderDao.GetFolders(toFolder.ID); foreach (var folderProject in foldersProject) { @@ -1314,34 +1340,29 @@ namespace ASC.Web.Files.Services.WCFService var filesPr = fileDao.GetFiles(folderProject.ID); var foldersPr = folderDao.GetFolders(folderProject.ID).Select(d => d.ID); - var recurseItems = MoveOrCopyFilesCheck(filesPr, foldersPr, toSub.ID); - foreach (var recurseItem in recurseItems) - { - result.Add(recurseItem.Key, recurseItem.Value); - } + MoveOrCopyFilesCheck(filesPr, foldersPr, toSub.ID, out var cFiles, out var cFolders); + checkedFiles.AddRange(cFiles); + checkedFolders.AddRange(cFolders); } } try { foreach (var pair in folderDao.CanMoveOrCopy(foldersId.ToArray(), toFolder.ID)) { - result.Add(pair.Key.ToString(), pair.Value); + checkedFolders.Add(pair.Key); } } catch (Exception e) { throw GenerateException(e); } - return result; } - public ItemList MoveOrCopyItems(ItemList items, T destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) + public ItemList MoveOrCopyItems(IEnumerable foldersId, IEnumerable filesId, object destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false) { ItemList result; - if (items.Count != 0) + if (foldersId.Any() || filesId.Any()) { - ParseArrayItems(items, out var foldersId, out var filesId); - result = FileOperationsManagerHelper.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders()); } else @@ -1351,6 +1372,7 @@ namespace ASC.Web.Files.Services.WCFService return result; } + public ItemList DeleteFile(string action, T fileId, bool ignoreException = false, bool deleteAfter = false, bool immediately = false) { return FileOperationsManagerHelper.DeleteFile(fileId, ignoreException, !deleteAfter, immediately, GetHttpHeaders()); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs index 1c426d8de1..e3cd8745b3 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxDaoBase.cs @@ -50,7 +50,15 @@ namespace ASC.Files.Thirdparty.Box { public override string Id { get => "box"; } - public BoxDaoBase(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public BoxDaoBase( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs index 584cebea03..3afd220c62 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFileDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -49,8 +50,26 @@ namespace ASC.Files.Thirdparty.Box { internal class BoxFileDao : BoxDaoBase, IFileDao { - public BoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public BoxDaoSelector BoxDaoSelector { get; } + public IFileDao FileDao { get; } + + public BoxFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + BoxDaoSelector boxDaoSelector, + IFileDao fileDao) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + BoxDaoSelector = boxDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -349,6 +368,31 @@ namespace ASC.Files.Thirdparty.Box .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); } + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, BoxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } + public string MoveFile(string fileId, string toFolderId) { var boxFile = GetBoxFile(fileId); @@ -369,6 +413,21 @@ namespace ASC.Files.Thirdparty.Box return MakeId(boxFile.Id); } + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + public File CopyFile(string fileId, string toFolderId) { var boxFile = GetBoxFile(fileId); @@ -386,6 +445,16 @@ namespace ASC.Files.Thirdparty.Box return ToFile(newBoxFile); } + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, BoxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } + public string FileRename(File file, string newTitle) { var boxFile = GetBoxFile(file.ID); @@ -484,7 +553,7 @@ namespace ASC.Files.Thirdparty.Box { if (uploadSession.Items.ContainsKey("TempPath")) { - System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } @@ -537,11 +606,6 @@ namespace ASC.Files.Thirdparty.Box throw new NotImplementedException(); } - public int MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs index 94d6fa46f2..c77a896723 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxFolderDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -47,8 +48,31 @@ namespace ASC.Files.Thirdparty.Box { internal class BoxFolderDao : BoxDaoBase, IFolderDao { - public BoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public BoxDaoSelector BoxDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public BoxFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + BoxDaoSelector boxDaoSelector, + IFileDao fileDao, + IFolderDao folderDao + ) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + BoxDaoSelector = boxDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -260,7 +284,47 @@ namespace ASC.Files.Thirdparty.Box ProviderInfo.CacheReset(toBoxFolder.Id); return MakeId(boxFolder.Id); - } + } + + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, BoxDaoSelector.GetFileDao(folderId), BoxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } + + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { @@ -278,12 +342,42 @@ namespace ASC.Files.Thirdparty.Box ProviderInfo.CacheReset(toBoxFolder.Id); return ToFolder(newBoxFolder); - } - + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, BoxDaoSelector.GetFileDao(folderId), BoxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } + + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); - } + } + + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); + } public string RenameFolder(Folder folder, string newTitle) { @@ -330,7 +424,17 @@ namespace ASC.Files.Thirdparty.Box public bool UseRecursiveOperation(string folderId, string toRootFolderId) { return false; - } + } + + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; + } public bool CanCalculateSubitems(string entryId) { @@ -406,16 +510,6 @@ namespace ASC.Files.Thirdparty.Box return null; } - public string MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - - int IFolderDao.MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs index ef23278eb2..ded07df49a 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -96,7 +96,7 @@ namespace ASC.Files.Thirdparty.Box } } - public BoxStorageDisposableWrapper Wrapper { get; } + public BoxStorageDisposableWrapper Wrapper { get; private set; } public BoxProviderInfoHelper BoxProviderInfoHelper { get; } public BoxProviderInfo( @@ -129,7 +129,8 @@ namespace ASC.Files.Thirdparty.Box { if (Wrapper != null) { - Wrapper.Dispose(); + Wrapper.Dispose(); + Wrapper = null; } CacheReset(); @@ -206,6 +207,7 @@ namespace ASC.Files.Thirdparty.Box if (Storage != null) { Storage.Close(); + Storage = null; } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs b/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs index e726e7afa8..745f9c4219 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/CachedProviderAccountDao.cs @@ -86,11 +86,11 @@ namespace ASC.Files.Thirdparty public override IProviderInfo GetProviderInfo(int linkId) { - var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); - if (!cache.TryGetValue(key, out var value)) - { - value = base.GetProviderInfo(linkId); - cache.TryAdd(key, value); + var key = _rootKey + linkId.ToString(CultureInfo.InvariantCulture); + if (!cache.TryGetValue(key, out var value)) + { + value = base.GetProviderInfo(linkId); + cache.TryAdd(key, value); } return value; } @@ -125,7 +125,7 @@ namespace ASC.Files.Thirdparty { public static DIHelper AddCachedProviderAccountDaoService(this DIHelper services) { - services.TryAddScoped(); + services.TryAddScoped(); services.TryAddSingleton(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 6c133e00c5..bb20c8a97e 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -49,8 +50,27 @@ namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxFileDao : DropboxDaoBase, IFileDao { - public DropboxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public DropboxDaoSelector DropboxDaoSelector { get; } + public IFileDao FileDao { get; } + + public DropboxFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + DropboxDaoSelector dropboxDaoSelector, + IFileDao fileDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + DropboxDaoSelector = dropboxDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -349,7 +369,22 @@ namespace ASC.Files.Thirdparty.Dropbox { return GetDropboxItems(folderId, false) .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); - } + } + + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } public string MoveFile(string fileId, string toFolderId) { @@ -372,8 +407,38 @@ namespace ASC.Files.Thirdparty.Dropbox public int MoveFile(string fileId, int toFolderId) { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, DropboxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } + + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + throw new NotImplementedException(); - } + } + + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, DropboxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } public File CopyFile(string fileId, string toFolderId) { @@ -535,7 +600,7 @@ namespace ASC.Files.Thirdparty.Dropbox { if (uploadSession.Items.ContainsKey("TempPath")) { - System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs index 0cf54aabd0..e7d93cf285 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -45,8 +46,30 @@ namespace ASC.Files.Thirdparty.Dropbox { internal class DropboxFolderDao : DropboxDaoBase, IFolderDao { - public DropboxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public DropboxDaoSelector DropboxDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public DropboxFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + DropboxDaoSelector dropboxDaoSelector, + IFileDao fileDao, + IFolderDao folderDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + DropboxDaoSelector = dropboxDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -240,7 +263,32 @@ namespace ASC.Files.Thirdparty.Dropbox ProviderInfo.CacheReset(MakeDropboxPath(dropboxFolder), true); var parentFolderPath = GetParentFolderPath(dropboxFolder); if (parentFolderPath != null) ProviderInfo.CacheReset(parentFolderPath); - } + } + + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, DropboxDaoSelector.GetFileDao(folderId), DropboxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { @@ -260,6 +308,31 @@ namespace ASC.Files.Thirdparty.Dropbox return MakeId(dropboxFolder); } + + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, DropboxDaoSelector.GetFileDao(folderId), DropboxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { @@ -278,9 +351,29 @@ namespace ASC.Files.Thirdparty.Dropbox return ToFolder(newDropboxFolder); } + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); } public string RenameFolder(Folder folder, string newTitle) @@ -323,6 +416,16 @@ namespace ASC.Files.Thirdparty.Dropbox public bool UseTrashForRemove(Folder folder) { return false; + } + + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; } public bool UseRecursiveOperation(string folderId, string toRootFolderId) @@ -404,11 +507,6 @@ namespace ASC.Files.Thirdparty.Dropbox return null; } - public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index a312b167ab..03dff45f83 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -170,6 +170,7 @@ namespace ASC.Files.Thirdparty.Dropbox public void Dispose() { Storage?.Close(); + Storage = null; } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index ffdc6f0052..028f1e2290 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -49,8 +50,27 @@ namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao { - public GoogleDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public GoogleDriveDaoSelector GoogleDriveDaoSelector { get; } + public IFileDao FileDao { get; } + + public GoogleDriveFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + GoogleDriveDaoSelector googleDriveDaoSelector, + IFileDao fileDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + GoogleDriveDaoSelector = googleDriveDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -343,6 +363,31 @@ namespace ASC.Files.Thirdparty.GoogleDrive .Any(file => file.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); } + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, GoogleDriveDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } + public string MoveFile(string fileId, string toFolderId) { var driveFile = GetDriveEntry(fileId); @@ -366,6 +411,31 @@ namespace ASC.Files.Thirdparty.GoogleDrive return MakeId(driveFile.Id); } + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, GoogleDriveDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } + public File CopyFile(string fileId, string toFolderId) { var driveFile = GetDriveEntry(fileId); @@ -531,7 +601,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive } else if (uploadSession.Items.ContainsKey("TempPath")) { - System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } @@ -584,16 +654,6 @@ namespace ASC.Files.Thirdparty.GoogleDrive return null; } - public string MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - int IFileDao.MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs index 3db958f5aa..7d310d07b4 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -45,8 +46,30 @@ namespace ASC.Files.Thirdparty.GoogleDrive { internal class GoogleDriveFolderDao : GoogleDriveDaoBase, IFolderDao { - public GoogleDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public GoogleDriveDaoSelector GoogleDriveDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public GoogleDriveFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + GoogleDriveDaoSelector googleDriveDaoSelector, + IFileDao fileDao, + IFolderDao folderDao + ) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + GoogleDriveDaoSelector = googleDriveDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -230,6 +253,32 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (parentDriveId != null) ProviderInfo.CacheReset(parentDriveId, true); } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, GoogleDriveDaoSelector.GetFileDao(folderId), GoogleDriveDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } + + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var driveFolder = GetDriveEntry(folderId); @@ -253,6 +302,31 @@ namespace ASC.Files.Thirdparty.GoogleDrive return MakeId(driveFolder.Id); } + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, GoogleDriveDaoSelector.GetFileDao(folderId), GoogleDriveDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var driveFolder = GetDriveEntry(folderId); @@ -270,11 +344,31 @@ namespace ASC.Files.Thirdparty.GoogleDrive return ToFolder(newDriveFolder); } + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); } + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); + } + public string RenameFolder(Folder folder, string newTitle) { var driveFolder = GetDriveEntry(folder.ID); @@ -321,6 +415,16 @@ namespace ASC.Files.Thirdparty.GoogleDrive return true; } + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return true; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return true; + } + public bool CanCalculateSubitems(string entryId) { return false; @@ -395,11 +499,6 @@ namespace ASC.Files.Thirdparty.GoogleDrive return null; } - public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index c85b4bb711..01d493e5d4 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -143,6 +143,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive if (Wrapper != null) { Wrapper.Dispose(); + Wrapper = null; } CacheReset(); diff --git a/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs index 2bf93669b1..fb74c661d7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -172,6 +172,7 @@ namespace ASC.Files.Thirdparty if (ProviderInfo != null) { ProviderInfo.Dispose(); + ProviderInfo = null; } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index c6054fe902..b8df9342d0 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -48,8 +49,27 @@ namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveFileDao : OneDriveDaoBase, IFileDao { - public OneDriveFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public OneDriveDaoSelector OneDriveDaoSelector { get; } + public IFileDao FileDao { get; } + + public OneDriveFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + OneDriveDaoSelector oneDriveDaoSelector, + IFileDao fileDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + OneDriveDaoSelector = oneDriveDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -342,7 +362,32 @@ namespace ASC.Files.Thirdparty.OneDrive { return GetOneDriveItems(folderId.ToString(), false) .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); - } + } + + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, OneDriveDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } public string MoveFile(string fileId, string toFolderId) { @@ -362,7 +407,32 @@ namespace ASC.Files.Thirdparty.OneDrive ProviderInfo.CacheReset(toOneDriveFolder.Id); return MakeId(onedriveFile.Id); - } + } + + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, OneDriveDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } public File CopyFile(string fileId, string toFolderId) { @@ -585,16 +655,6 @@ namespace ASC.Files.Thirdparty.OneDrive throw new NotImplementedException(); } - public string MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - int IFileDao.MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs index ae5dfbbe80..ec4b496bf0 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -45,8 +46,30 @@ namespace ASC.Files.Thirdparty.OneDrive { internal class OneDriveFolderDao : OneDriveDaoBase, IFolderDao { - public OneDriveFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public OneDriveDaoSelector OneDriveDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public OneDriveFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + OneDriveDaoSelector oneDriveDaoSelector, + IFileDao fileDao, + IFolderDao folderDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + OneDriveDaoSelector = oneDriveDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -236,7 +259,32 @@ namespace ASC.Files.Thirdparty.OneDrive ProviderInfo.CacheReset(onedriveFolder.Id); var parentFolderId = GetParentFolderId(onedriveFolder); if (parentFolderId != null) ProviderInfo.CacheReset(parentFolderId); - } + } + + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, OneDriveDaoSelector.GetFileDao(folderId), OneDriveDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { @@ -256,7 +304,32 @@ namespace ASC.Files.Thirdparty.OneDrive ProviderInfo.CacheReset(toOneDriveFolder.Id); return MakeId(onedriveFolder.Id); - } + } + + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, OneDriveDaoSelector.GetFileDao(folderId), OneDriveDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { @@ -275,9 +348,29 @@ namespace ASC.Files.Thirdparty.OneDrive return ToFolder(newOneDriveFolder); } + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); } public string RenameFolder(Folder folder, string newTitle) @@ -331,7 +424,17 @@ namespace ASC.Files.Thirdparty.OneDrive public bool UseRecursiveOperation(string folderId, string toRootFolderId) { return false; - } + } + + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; + } public bool CanCalculateSubitems(string entryId) { @@ -407,11 +510,6 @@ namespace ASC.Files.Thirdparty.OneDrive return null; } - public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index 9e704bd508..ab6498b81a 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -80,7 +80,7 @@ namespace ASC.Files.Thirdparty.OneDrive public string ProviderKey { get; set; } public FolderType RootFolderType { get; set; } - public OneDriveStorageDisposableWrapper Wrapper { get; } + public OneDriveStorageDisposableWrapper Wrapper { get; private set; } public OneDriveProviderInfoHelper OneDriveProviderInfoHelper { get; } public OneDriveProviderInfo( @@ -114,6 +114,7 @@ namespace ASC.Files.Thirdparty.OneDrive if (Wrapper != null) { Wrapper.Dispose(); + Wrapper = null; } CacheReset(); @@ -182,6 +183,7 @@ namespace ASC.Files.Thirdparty.OneDrive if (Storage != null && Storage.IsOpened) { Storage.Close(); + Storage = null; } } } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index fe70787427..a2a4d38993 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Thirdparty; @@ -48,8 +49,11 @@ namespace ASC.Files.Thirdparty.ProviderDao { private readonly List Selectors; + private int TenantID { get; set; } + public ProviderDaoBase( IServiceProvider serviceProvider, + TenantManager tenantManager, SecurityDao securityDao, TagDao tagDao, CrossDao crossDao) @@ -58,6 +62,8 @@ namespace ASC.Files.Thirdparty.ProviderDao SecurityDao = securityDao; TagDao = tagDao; CrossDao = crossDao; + TenantID = tenantManager.GetCurrentTenant().TenantId; + Selectors = new List { //Fill in selectors @@ -122,9 +128,12 @@ namespace ASC.Files.Thirdparty.ProviderDao { var fromSelector = GetSelector(fromFileId); using var scope = ServiceProvider.CreateScope(); + var tenantManager = scope.ServiceProvider.GetService(); + tenantManager.SetCurrentTenant(TenantID); + return CrossDao.PerformCrossDaoFileCopy( fromFileId, fromSelector.GetFileDao(fromFileId), fromSelector.ConvertId, - toFolderId, scope.ServiceProvider.GetService(), r => r, + toFolderId, scope.ServiceProvider.GetService>(), r => r, deleteSourceFile); } @@ -146,7 +155,7 @@ namespace ASC.Files.Thirdparty.ProviderDao return CrossDao.PerformCrossDaoFolderCopy( fromFolderId, fromSelector.GetFolderDao(fromFolderId), fromSelector.GetFileDao(fromFolderId), fromSelector.ConvertId, - toRootFolderId, scope.ServiceProvider.GetService(), scope.ServiceProvider.GetService(), r => r, + toRootFolderId, scope.ServiceProvider.GetService(), scope.ServiceProvider.GetService>(), r => r, deleteSourceFolder, cancellationToken); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index d7b7642ab6..4d747e56e8 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using ASC.Common; +using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Thirdparty; @@ -41,10 +42,11 @@ namespace ASC.Files.Thirdparty.ProviderDao { public ProviderFileDao( IServiceProvider serviceProvider, + TenantManager tenantManager, SecurityDao securityDao, TagDao tagDao, CrossDao crossDao) - : base(serviceProvider, securityDao, tagDao, crossDao) + : base(serviceProvider, tenantManager, securityDao, tagDao, crossDao) { } @@ -310,6 +312,27 @@ namespace ASC.Files.Thirdparty.ProviderDao return fileDao.IsExist(title, selector.ConvertId(folderId.ToString())); } + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var movedFile = PerformCrossDaoFileCopy(fileId, toFolderId, true); + return movedFile.ID; + } + public string MoveFile(string fileId, string toFolderId) { var selector = GetSelector(fileId); @@ -323,6 +346,26 @@ namespace ASC.Files.Thirdparty.ProviderDao return fileDao.MoveFile(selector.ConvertId(fileId), selector.ConvertId(toFolderId)); } + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + + public File CopyFile(string fileId, int toFolderId) + { + return PerformCrossDaoFileCopy(fileId, toFolderId, false); + } + public File CopyFile(string fileId, string toFolderId) { var selector = GetSelector(fileId); @@ -466,12 +509,6 @@ namespace ASC.Files.Thirdparty.ProviderDao throw new NotImplementedException(); } - public int MoveFile(string fileId, int toFolderId) - { - var movedFile = PerformCrossDaoFileCopy(fileId, toFolderId, true); - return movedFile.ID; - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs index 711a69590e..98493d5461 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderFolderDao.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Threading; using ASC.Common; +using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Thirdparty; @@ -40,10 +41,11 @@ namespace ASC.Files.Thirdparty.ProviderDao { public ProviderFolderDao( IServiceProvider serviceProvider, + TenantManager tenantManager, SecurityDao securityDao, TagDao tagDao, CrossDao crossDao) - : base(serviceProvider, securityDao, tagDao, crossDao) + : base(serviceProvider, tenantManager, securityDao, tagDao, crossDao) { } @@ -172,6 +174,21 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); folderDao.DeleteFolder(selector.ConvertId(folderId)); } + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var selector = GetSelector(folderId); @@ -190,6 +207,26 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); return newFolder.ID; } + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + return PerformCrossDaoFolderCopy(folderId, toFolderId, false, cancellationToken); + } + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var selector = GetSelector(folderId); @@ -199,6 +236,26 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); : folderDao.CopyFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null); } + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { if (!folderIds.Any()) return new Dictionary(); @@ -243,6 +300,16 @@ filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare); return folderDao.UseTrashForRemove(folder); } + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; + } + public bool UseRecursiveOperation(string folderId, string toRootFolderId) { var selector = GetSelector(folderId); diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs index 4f3e76cf73..36b88b47b7 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderSecutiryDao.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; +using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Security; @@ -40,11 +41,13 @@ namespace ASC.Files.Thirdparty.ProviderDao { internal class ProviderSecurityDao : ProviderDaoBase, ISecurityDao { - public ProviderSecurityDao(IServiceProvider serviceProvider, + public ProviderSecurityDao( + IServiceProvider serviceProvider, + TenantManager tenantManager, SecurityDao securityDao, TagDao tagDao, CrossDao crossDao) - : base(serviceProvider, securityDao, tagDao, crossDao) + : base(serviceProvider, tenantManager, securityDao, tagDao, crossDao) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs index 3ad987e620..d96feddf28 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/ProviderDao/ProviderTagDao.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using ASC.Common; +using ASC.Core; using ASC.Files.Core; using ASC.Files.Core.Data; using ASC.Files.Core.Thirdparty; @@ -38,10 +39,11 @@ namespace ASC.Files.Thirdparty.ProviderDao { public ProviderTagDao( IServiceProvider serviceProvider, + TenantManager tenantManager, SecurityDao securityDao, TagDao tagDao, CrossDao crossDao) - : base(serviceProvider, securityDao, tagDao, crossDao) + : base(serviceProvider, tenantManager, securityDao, tagDao, crossDao) { } diff --git a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs index 56b41aa494..001e1cd44d 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/RegexDaoSelectorBase.cs @@ -115,13 +115,14 @@ namespace ASC.Files.Thirdparty private T1 GetDao(string id) where T1 : ThirdPartyProviderDao { - if (Providers.ContainsKey(id)) return (T1)Providers[id]; + var providerKey = $"{id}{typeof(T1)}"; + if (Providers.ContainsKey(providerKey)) return (T1)Providers[providerKey]; var res = ServiceProvider.GetService(); res.Init(GetInfo(id), this); - Providers.Add(id, res); + Providers.Add(providerKey, res); return res; } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 6983c6fbb9..4e737b9592 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -47,8 +48,27 @@ namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointFileDao : SharePointDaoBase, IFileDao { - public SharePointFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public SharePointDaoSelector SharePointDaoSelector { get; } + public IFileDao FileDao { get; } + + public SharePointFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + SharePointDaoSelector sharePointDaoSelector, + IFileDao fileDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + SharePointDaoSelector = sharePointDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -295,6 +315,31 @@ namespace ASC.Files.Thirdparty.SharePoint .Any(item => item.Name.Equals(title, StringComparison.InvariantCultureIgnoreCase)); } + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, SharePointDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } + public string MoveFile(string fileId, string toFolderId) { var newFileId = ProviderInfo.MoveFile(fileId, toFolderId); @@ -302,6 +347,31 @@ namespace ASC.Files.Thirdparty.SharePoint return newFileId; } + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, SharePointDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } + public File CopyFile(string fileId, string toFolderId) { return ProviderInfo.ToFile(ProviderInfo.CopyFile(fileId, toFolderId)); @@ -414,16 +484,6 @@ namespace ASC.Files.Thirdparty.SharePoint throw new NotImplementedException(); } - public string MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - int IFileDao.MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs index 3aed0f7865..6e3c575ccf 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointFolderDao.cs @@ -36,6 +36,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -45,8 +46,30 @@ namespace ASC.Files.Thirdparty.SharePoint { internal class SharePointFolderDao : SharePointDaoBase, IFolderDao { - public SharePointFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public SharePointDaoSelector SharePointDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public SharePointFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + SharePointDaoSelector sharePointDaoSelector, + IFileDao fileDao, + IFolderDao folderDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + SharePointDaoSelector = sharePointDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -235,6 +258,31 @@ namespace ASC.Files.Thirdparty.SharePoint ProviderInfo.DeleteFolder(folderId); } + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, SharePointDaoSelector.GetFileDao(folderId), SharePointDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var newFolderId = ProviderInfo.MoveFolder(folderId, toFolderId); @@ -242,16 +290,61 @@ namespace ASC.Files.Thirdparty.SharePoint return newFolderId; } + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { return ProviderInfo.ToFolder(ProviderInfo.CopyFolder(folderId, toFolderId)); } + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, SharePointDaoSelector.GetFileDao(folderId), SharePointDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } + + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); } + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); + } + public string RenameFolder(Folder folder, string newTitle) { var oldId = ProviderInfo.MakeId(folder.ID); @@ -285,6 +378,16 @@ namespace ASC.Files.Thirdparty.SharePoint return false; } + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; + } + public bool UseRecursiveOperation(string folderId, string toRootFolderId) { return false; @@ -363,11 +466,6 @@ namespace ASC.Files.Thirdparty.SharePoint return null; } - public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs index 881575cfc3..88f0119ab3 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/SharePoint/SharePointProviderInfo.cs @@ -91,7 +91,12 @@ namespace ASC.Files.Thirdparty.SharePoint public void InvalidateStorage() { - clientContext.Dispose(); + if (clientContext != null) + { + clientContext.Dispose(); + clientContext = null; + } + SharePointProviderInfoHelper.Invalidate(); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index c76d070de6..a6629e20f5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -41,6 +41,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Files.Services.DocumentService; @@ -52,8 +53,27 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao { - public SharpBoxFileDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public SharpBoxDaoSelector SharpBoxDaoSelector { get; } + public IFileDao FileDao { get; } + + public SharpBoxFileDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + SharpBoxDaoSelector sharpBoxDaoSelector, + IFileDao fileDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + SharpBoxDaoSelector = sharpBoxDaoSelector; + FileDao = fileDao; } public void InvalidateCache(string fileId) @@ -393,6 +413,31 @@ namespace ASC.Files.Thirdparty.Sharpbox return false; } + public TTo MoveFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tId), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFile(fileId, tsId), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, SharpBoxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + true); + + return moved.ID; + } + public string MoveFile(string fileId, string toFolderId) { var entry = GetFileById(fileId); @@ -410,6 +455,21 @@ namespace ASC.Files.Thirdparty.Sharpbox return newFileId; } + public File CopyFile(string fileId, TTo toFolderId) + { + if (toFolderId is int tId) + { + return CopyFile(fileId, tId) as File; + } + + if (toFolderId is string tsId) + { + return CopyFile(fileId, tsId) as File; + } + + throw new NotImplementedException(); + } + public File CopyFile(string fileId, string toFolderId) { var file = GetFileById(fileId); @@ -418,6 +478,16 @@ namespace ASC.Files.Thirdparty.Sharpbox return ToFile(GetFolderById(toFolderId).FirstOrDefault(x => x.Name == file.Name)); } + public File CopyFile(string fileId, int toFolderId) + { + var moved = CrossDao.PerformCrossDaoFileCopy( + fileId, this, SharpBoxDaoSelector.ConvertId, + toFolderId, FileDao, r => r, + false); + + return moved; + } + public string FileRename(File file, string newTitle) { var entry = GetFileById(file.ID); @@ -577,7 +647,7 @@ namespace ASC.Files.Thirdparty.Sharpbox } else if (uploadSession.Items.ContainsKey("TempPath")) { - System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); + File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } @@ -640,16 +710,6 @@ namespace ASC.Files.Thirdparty.Sharpbox throw new NotImplementedException(); } - public string MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - - int IFileDao.MoveFile(string fileId, int toFolderId) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs index 452b0924eb..93bffcb4c5 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs @@ -41,6 +41,7 @@ using ASC.Core.Common.EF; using ASC.Core.Tenants; using ASC.Files.Core; using ASC.Files.Core.EF; +using ASC.Files.Core.Thirdparty; using ASC.Files.Resources; using ASC.Web.Core.Files; using ASC.Web.Studio.Core; @@ -51,8 +52,30 @@ namespace ASC.Files.Thirdparty.Sharpbox { internal class SharpBoxFolderDao : SharpBoxDaoBase, IFolderDao { - public SharpBoxFolderDao(IServiceProvider serviceProvider, UserManager userManager, TenantManager tenantManager, TenantUtil tenantUtil, DbContextManager dbContextManager, SetupInfo setupInfo, IOptionsMonitor monitor, FileUtility fileUtility) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) + public CrossDao CrossDao { get; } + public SharpBoxDaoSelector SharpBoxDaoSelector { get; } + public IFileDao FileDao { get; } + public IFolderDao FolderDao { get; } + + public SharpBoxFolderDao( + IServiceProvider serviceProvider, + UserManager userManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + DbContextManager dbContextManager, + SetupInfo setupInfo, + IOptionsMonitor monitor, + FileUtility fileUtility, + CrossDao crossDao, + SharpBoxDaoSelector sharpBoxDaoSelector, + IFileDao fileDao, + IFolderDao folderDao) + : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility) { + CrossDao = crossDao; + SharpBoxDaoSelector = sharpBoxDaoSelector; + FileDao = fileDao; + FolderDao = folderDao; } public Folder GetFolder(string folderId) @@ -264,6 +287,31 @@ namespace ASC.Files.Thirdparty.Sharpbox return false; } + public TTo MoveFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tId, cancellationToken), typeof(TTo)); + } + + if (toFolderId is string tsId) + { + return (TTo)Convert.ChangeType(MoveFolder(folderId, tsId, cancellationToken), typeof(TTo)); + } + + throw new NotImplementedException(); + } + + public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, SharpBoxDaoSelector.GetFileDao(folderId), SharpBoxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + true, cancellationToken); + + return moved.ID; + } + public string MoveFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var entry = GetFolderById(folderId); @@ -281,6 +329,31 @@ namespace ASC.Files.Thirdparty.Sharpbox return newFolderId; } + public Folder CopyFolder(string folderId, TTo toFolderId, CancellationToken? cancellationToken) + { + if (toFolderId is int tId) + { + return CopyFolder(folderId, tId, cancellationToken) as Folder; + } + + if (toFolderId is string tsId) + { + return CopyFolder(folderId, tsId, cancellationToken) as Folder; + } + + throw new NotImplementedException(); + } + + public Folder CopyFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) + { + var moved = CrossDao.PerformCrossDaoFolderCopy( + folderId, this, SharpBoxDaoSelector.GetFileDao(folderId), SharpBoxDaoSelector.ConvertId, + toFolderId, FolderDao, FileDao, r => r, + false, cancellationToken); + + return moved; + } + public Folder CopyFolder(string folderId, string toFolderId, CancellationToken? cancellationToken) { var folder = GetFolderById(folderId); @@ -289,11 +362,31 @@ namespace ASC.Files.Thirdparty.Sharpbox return ToFolder(GetFolderById(toFolderId).OfType().FirstOrDefault(x => x.Name == folder.Name)); } + public IDictionary CanMoveOrCopy(string[] folderIds, TTo to) + { + if (to is int tId) + { + return CanMoveOrCopy(folderIds, tId); + } + + if (to is string tsId) + { + return CanMoveOrCopy(folderIds, tsId); + } + + throw new NotImplementedException(); + } + public IDictionary CanMoveOrCopy(string[] folderIds, string to) { return new Dictionary(); } + public IDictionary CanMoveOrCopy(string[] folderIds, int to) + { + return new Dictionary(); + } + public string RenameFolder(Folder folder, string newTitle) { var entry = GetFolderById(folder.ID); @@ -342,6 +435,17 @@ namespace ASC.Files.Thirdparty.Sharpbox return false; } + + public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) + { + return false; + } + + public bool UseRecursiveOperation(string folderId, int toRootFolderId) + { + return false; + } + public bool UseRecursiveOperation(string folderId, string toRootFolderId) { return false; @@ -426,11 +530,6 @@ namespace ASC.Files.Thirdparty.Sharpbox return null; } - public int MoveFolder(string folderId, int toFolderId, CancellationToken? cancellationToken) - { - throw new NotImplementedException(); - } - #endregion } diff --git a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs index de89024cde..89a5c654e9 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/Sharpbox/SharpBoxProviderInfo.cs @@ -115,6 +115,7 @@ namespace ASC.Files.Thirdparty.Sharpbox if (Wrapper != null) { Wrapper.Dispose(); + Wrapper = null; } } @@ -125,7 +126,7 @@ namespace ASC.Files.Thirdparty.Sharpbox } public FolderType RootFolderType { get; set; } - public SharpBoxStorageDisposableWrapper Wrapper { get; } + public SharpBoxStorageDisposableWrapper Wrapper { get; private set; } } class SharpBoxStorageDisposableWrapper : IDisposable @@ -172,6 +173,7 @@ namespace ASC.Files.Thirdparty.Sharpbox if (Storage != null && Storage.IsOpened) { Storage.Close(); + Storage = null; } } } diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index 5ddef80482..9714155318 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -365,10 +365,10 @@ namespace ASC.Files.Helpers return GetFileInfo(fileId); } - public IEnumerable> DeleteFile(T fileId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFile(T fileId, bool deleteAfter, bool immediately) { return FileStorageService.DeleteFile("delete", fileId, false, deleteAfter, immediately) - .Select(FileOperationWraperHelper.Get); + .Select(FileOperationWraperHelper.Get); } public IEnumerable> StartConversion(T fileId) @@ -402,68 +402,69 @@ namespace ASC.Files.Helpers }); } - public IEnumerable> DeleteFolder(T folderId, bool deleteAfter, bool immediately) + public IEnumerable DeleteFolder(T folderId, bool deleteAfter, bool immediately) { return FileStorageService.DeleteFile("delete", folderId, false, deleteAfter, immediately) - .Select(FileOperationWraperHelper.Get); + .Select(FileOperationWraperHelper.Get); } - public IEnumerable> MoveOrCopyBatchCheck(BatchModel batchModel) + public IEnumerable MoveOrCopyBatchCheck(BatchModel batchModel) { - var itemList = new ItemList(); + FileStorageService.MoveOrCopyFilesCheck(batchModel.FileIds, batchModel.FolderIds, batchModel.DestFolderId, out var checkedFiles, out var checkedFolders); - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); + var entries = FileStorageService.GetItems(checkedFiles.OfType().Select(Convert.ToInt32), checkedFiles.OfType().Select(Convert.ToInt32), FilterType.FilesOnly, false, "", ""); - var ids = FileStorageService.MoveOrCopyFilesCheck(itemList, batchModel.DestFolderId).Keys.Select(id => "file_" + id); + entries.AddRange(FileStorageService.GetItems(checkedFiles.OfType(), checkedFiles.OfType(), FilterType.FilesOnly, false, "", "")); - var entries = FileStorageService.GetItems(new ItemList(ids), FilterType.FilesOnly, false, "", ""); - return entries.Select(x => FileWrapperHelper.Get((File)x)); + return entries.Select(r => + { + FileEntryWrapper wrapper = null; + if (r is Folder fol1) + { + wrapper = FolderWrapperHelper.Get(fol1); + } + if (r is Folder fol2) + { + wrapper = FolderWrapperHelper.Get(fol2); + } + + return wrapper; + }); } - public IEnumerable> MoveBatchItems(BatchModel batchModel) + public IEnumerable MoveBatchItems(BatchModel batchModel) { - var itemList = new ItemList(); - - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter) - .Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(batchModel.FolderIds, batchModel.FileIds, batchModel.DestFolderId, batchModel.ConflictResolveType, false, batchModel.DeleteAfter) + .Select(FileOperationWraperHelper.Get); } - public IEnumerable> CopyBatchItems(BatchModel batchModel) + public IEnumerable CopyBatchItems(BatchModel batchModel) { - var itemList = new ItemList(); - - itemList.AddRange((batchModel.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((batchModel.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MoveOrCopyItems(itemList, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter) - .Select(FileOperationWraperHelper.Get); + return FileStorageService.MoveOrCopyItems(batchModel.FolderIds, batchModel.FileIds, batchModel.DestFolderId, batchModel.ConflictResolveType, true, batchModel.DeleteAfter) + .Select(FileOperationWraperHelper.Get); } - public IEnumerable> MarkAsRead(BaseBatchModel model) + public IEnumerable MarkAsRead(BaseBatchModel model) { var itemList = new ItemList(); itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); } - public IEnumerable> TerminateTasks() + public IEnumerable TerminateTasks() { - return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); + return FileStorageService.TerminateTasks().Select(FileOperationWraperHelper.Get); } - public IEnumerable> GetOperationStatuses() + public IEnumerable GetOperationStatuses() { - return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); + return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); } - public IEnumerable> BulkDownload(DownloadModel model) + public IEnumerable BulkDownload(DownloadModel model) { var itemList = new Dictionary(); @@ -482,12 +483,12 @@ namespace ASC.Files.Helpers itemList.Add("folder_" + folderId, string.Empty); } - return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); } - public IEnumerable> EmptyTrash() + public IEnumerable EmptyTrash() { - return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); + return FileStorageService.EmptyTrash().Select(FileOperationWraperHelper.Get); } public IEnumerable> GetFileVersionInfo(T fileId) diff --git a/products/ASC.Files/Server/Helpers/FilesMessageService.cs b/products/ASC.Files/Server/Helpers/FilesMessageService.cs index 0ca1524848..0cff17fafa 100644 --- a/products/ASC.Files/Server/Helpers/FilesMessageService.cs +++ b/products/ASC.Files/Server/Helpers/FilesMessageService.cs @@ -77,12 +77,12 @@ namespace ASC.Web.Files.Helpers SendHeadersMessage(headers, action, MessageTarget.Create(entry.ID), description); } - public void Send(FileEntry entry1, FileEntry entry2, Dictionary headers, MessageAction action, params string[] description) + public void Send(FileEntry entry1, FileEntry entry2, Dictionary headers, MessageAction action, params string[] description) { // do not log actions in users folder if (entry1 == null || entry2 == null || entry1.RootFolderType == FolderType.USER || entry2.RootFolderType == FolderType.USER) return; - SendHeadersMessage(headers, action, MessageTarget.Create(new[] { entry1.ID, entry2.ID }), description); + SendHeadersMessage(headers, action, MessageTarget.Create(new[] { entry1.ID.ToString(), entry2.ID.ToString() }), description); } private void SendHeadersMessage(Dictionary headers, MessageAction action, MessageTarget target, params string[] description) diff --git a/products/ASC.Files/Server/Model/BatchModel.cs b/products/ASC.Files/Server/Model/BatchModel.cs index a3a9225141..17a5a949c1 100644 --- a/products/ASC.Files/Server/Model/BatchModel.cs +++ b/products/ASC.Files/Server/Model/BatchModel.cs @@ -27,9 +27,9 @@ namespace ASC.Files.Model public bool Immediately { get; set; } } - public class BatchModel : BaseBatchModel + public class BatchModel : BaseBatchModel { - public T DestFolderId { get; set; } + public object DestFolderId { get; set; } public FileConflictResolveType ConflictResolveType { get; set; } public bool DeleteAfter { get; set; } } diff --git a/products/ASC.Files/Server/Model/FileOperationWraper.cs b/products/ASC.Files/Server/Model/FileOperationWraper.cs index 905b3b45c6..682c2e093f 100644 --- a/products/ASC.Files/Server/Model/FileOperationWraper.cs +++ b/products/ASC.Files/Server/Model/FileOperationWraper.cs @@ -40,7 +40,7 @@ namespace ASC.Api.Documents /// /// [DataContract(Name = "operation_result", Namespace = "")] - public class FileOperationWraper + public class FileOperationWraper { /// /// @@ -80,12 +80,12 @@ namespace ASC.Api.Documents /// /// [DataMember(Name = "files", IsRequired = true, EmitDefaultValue = true)] - public List> Files { get; set; } + public List Files { get; set; } /// /// [DataMember(Name = "folders", IsRequired = true, EmitDefaultValue = true)] - public List> Folders { get; set; } + public List Folders { get; set; } /// /// @@ -96,9 +96,9 @@ namespace ASC.Api.Documents /// /// /// - public static FileOperationWraper GetSample() + public static FileOperationWraper GetSample() { - return new FileOperationWraper + return new FileOperationWraper { Id = Guid.NewGuid().ToString(), OperationType = FileOperationType.Move, @@ -107,8 +107,8 @@ namespace ASC.Api.Documents //Result = "folder_1,file_1", Error = "", Processed = "1", - Files = new List> { FileWrapper.GetSample() }, - Folders = new List> { FolderWrapper.GetSample() } + Files = new List { FileWrapper.GetSample() }, + Folders = new List { FolderWrapper.GetSample() } }; } } @@ -132,9 +132,9 @@ namespace ASC.Api.Documents CommonLinkUtility = commonLinkUtility; } - public FileOperationWraper Get(FileOperationResult o) + public FileOperationWraper Get(FileOperationResult o) { - var result = new FileOperationWraper + var result = new FileOperationWraper { Id = o.Id, OperationType = o.OperationType, @@ -149,23 +149,51 @@ namespace ASC.Api.Documents var arr = o.Result.Split(':'); var folders = arr .Where(s => s.StartsWith("folder_")) - .Select(s => s.Substring(7)) - .Select(r => (T)Convert.ChangeType(r, typeof(T))); + .Select(s => s.Substring(7)); if (folders.Any()) { - var folderDao = DaoFactory.GetFolderDao(); - result.Folders = folderDao.GetFolders(folders.ToArray()).Select(r => FolderWrapperHelper.Get(r)).ToList(); + var fInt = new List(); + var fString = new List(); + + foreach (var folder in folders) + { + if (int.TryParse(folder, out var f)) + { + fInt.Add(f); + } + else + { + fString.Add(folder); + } + } + + result.Folders = GetFolders(folders).ToList(); + result.Folders.AddRange(GetFolders(fInt)); } var files = arr .Where(s => s.StartsWith("file_")) - .Select(s => s.Substring(5)) - .Select(r => (T)Convert.ChangeType(r, typeof(T))); + .Select(s => s.Substring(5)); if (files.Any()) { - var fileDao = DaoFactory.GetFileDao(); - result.Files = fileDao.GetFiles(files.ToArray()).Select(r => FilesWrapperHelper.Get(r)).ToList(); + var fInt = new List(); + var fString = new List(); + + foreach (var file in files) + { + if (int.TryParse(file, out var f)) + { + fInt.Add(f); + } + else + { + fString.Add(file); + } + } + + result.Files = GetFiles(fString).ToList(); + result.Files.AddRange(GetFiles(fInt)); } if (result.OperationType == FileOperationType.Download) @@ -175,6 +203,22 @@ namespace ASC.Api.Documents } return result; + + IEnumerable GetFolders(IEnumerable folders) + { + var folderDao = DaoFactory.GetFolderDao(); + return folderDao.GetFolders(folders.ToArray()) + .Select(FolderWrapperHelper.Get) + .Cast(); + } + + IEnumerable GetFiles(IEnumerable files) + { + var fileDao = DaoFactory.GetFileDao(); + return fileDao.GetFiles(files.ToArray()) + .Select(FilesWrapperHelper.Get) + .Cast(); + } } } public static class FileOperationWraperHelperExtention diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs index 190b1da07b..d1fcfa2c7f 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -46,7 +46,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public bool Immediately { get; } public Dictionary Headers { get; } - public FileDeleteOperationData(List folders, List files, Tenant tenant, + public FileDeleteOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, + bool holdResult = true, bool ignoreException = false, bool immediately = false, Dictionary headers = null) + : this(folders.OfType(), files.OfType(), tenant, holdResult, ignoreException, immediately, headers) + { + } + + public FileDeleteOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, bool holdResult = true, bool ignoreException = false, bool immediately = false, Dictionary headers = null) : base(folders, files, tenant, holdResult) { @@ -107,7 +113,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } if (root != null) { - Status += string.Format("folder_{0}{1}", root.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", root.ID, SPLIT_CHAR); } DeleteFiles(Files, scope); @@ -157,7 +163,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations else { var immediately = _immediately || !FolderDao.UseTrashForRemove(folder); - if (immediately && FolderDao.UseRecursiveOperation(folder.ID, default)) + if (immediately && FolderDao.UseRecursiveOperation(folder.ID, default(T))) { DeleteFiles(FileDao.GetFiles(folder.ID), scope); DeleteFolders(FolderDao.GetFolders(folder.ID).Select(f => f.ID).ToList(), scope); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs index 0b359cc704..a3b42adc43 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs @@ -200,7 +200,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations using (var zip = new ZipOutputStream(stream, true)) { zip.CompressionLevel = Ionic.Zlib.CompressionLevel.Level3; - zip.AlternateEncodingUsage = Ionic.Zip.ZipOption.AsNecessary; + zip.AlternateEncodingUsage = ZipOption.AsNecessary; zip.AlternateEncoding = Encoding.UTF8; foreach (var path in entriesPathId.AllKeys) diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs index dd0b82f610..534380ef8e 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs @@ -97,7 +97,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations .GetRootFoldersIdMarkedAsNew() .Select(item => string.Format("new_{{\"key\"? \"{0}\", \"value\"? \"{1}\"}}", item.Key, item.Value)); - Status += string.Join(FileOperation.SPLIT_CHAR, newrootfolder.ToArray()); + Status += string.Join(SPLIT_CHAR, newrootfolder.ToArray()); } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index 97ba0bd12a..acf96e8270 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -41,17 +41,50 @@ using Microsoft.Extensions.DependencyInjection; namespace ASC.Web.Files.Services.WCFService.FileOperations { + class FileMoveCopyOperation : ComposeFileOperation, FileMoveCopyOperationData> + { + public FileMoveCopyOperation(IServiceProvider serviceProvider, + FileOperation, string> thirdPartyOperation, + FileOperation, int> daoOperation) + : base(serviceProvider, thirdPartyOperation, daoOperation) + { + + } + + public override FileOperationType OperationType + { + get + { + return ThirdPartyOperation.OperationType; + } + } + } + internal class FileMoveCopyOperationData : FileOperationData { - public T ToFolderId { get; } + public string ThirdpartyFolderId { get; } + public int DaoFolderId { get; } public bool Copy { get; } public FileConflictResolveType ResolveType { get; } public Dictionary Headers { get; } - public FileMoveCopyOperationData(List folders, List files, Tenant tenant, T toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary headers = null) + public FileMoveCopyOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, object toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary headers = null) + : this(folders.OfType(), files.OfType(), tenant, toFolderId, copy, resolveType, holdResult, headers) + { + } + + public FileMoveCopyOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, object toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary headers = null) : base(folders, files, tenant, holdResult) { - ToFolderId = toFolderId; + if (toFolderId is string thirdpartyFolderId) + { + ThirdpartyFolderId = thirdpartyFolderId; + } + else if (toFolderId is long daoFolderId) + { + DaoFolderId = (int)daoFolderId; + } + Copy = copy; ResolveType = resolveType; Headers = headers; @@ -60,10 +93,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations class FileMoveCopyOperation : FileOperation, T> { - private readonly T _toFolderId; + private readonly int DaoFolderId; + private readonly string ThirdpartyFolderId; private readonly bool _copy; private readonly FileConflictResolveType _resolveType; - private readonly List> _needToMark = new List>(); private readonly Dictionary _headers; @@ -75,7 +108,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public FileMoveCopyOperation(IServiceProvider serviceProvider, FileMoveCopyOperationData data) : base(serviceProvider, data) { - _toFolderId = data.ToFolderId; + DaoFolderId = data.DaoFolderId; + ThirdpartyFolderId = data.ThirdpartyFolderId; _copy = data.Copy; _resolveType = data.ResolveType; @@ -84,16 +118,30 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations protected override void Do(IServiceScope scope) { - var fileMarker = scope.ServiceProvider.GetService(); + if (DaoFolderId != 0) + { + Do(scope, DaoFolderId); + } - Status += string.Format("folder_{0}{1}", _toFolderId, FileOperation.SPLIT_CHAR); + if (!string.IsNullOrEmpty(ThirdpartyFolderId)) + { + Do(scope, ThirdpartyFolderId); + } + } + + private void Do(IServiceScope scope, TTo tto) + { + var fileMarker = scope.ServiceProvider.GetService(); + var folderDao = scope.ServiceProvider.GetService>(); + + Status += string.Format("folder_{0}{1}", DaoFolderId, SPLIT_CHAR); //TODO: check on each iteration? - var toFolder = FolderDao.GetFolder(_toFolderId); + var toFolder = folderDao.GetFolder(tto); if (toFolder == null) return; if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); - if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID))) + if (folderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Any(r => r.ToString() == parent.ID.ToString()))) { Error = FilesCommonResource.ErrorMassage_FolderCopyError; return; @@ -108,20 +156,27 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (toFolder.RootFolderType == FolderType.TRASH) throw new InvalidOperationException("Can not copy to Trash."); } - MoveOrCopyFolders(scope, Folders, toFolder, _copy); - MoveOrCopyFiles(scope, Files, toFolder, _copy); + var needToMark = new List>(); - _needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); + needToMark.AddRange(MoveOrCopyFolders(scope, Folders, toFolder, _copy)); + needToMark.AddRange(MoveOrCopyFiles(scope, Files, toFolder, _copy)); + + needToMark.Distinct().ToList().ForEach(x => fileMarker.MarkAsNew(x)); } - private void MoveOrCopyFolders(IServiceScope scope, List folderIds, Folder toFolder, bool copy) + private List> MoveOrCopyFolders(IServiceScope scope, List folderIds, Folder toFolder, bool copy) { - if (folderIds.Count == 0) return; + var needToMark = new List>(); + + if (folderIds.Count == 0) return needToMark; var filesMessageService = scope.ServiceProvider.GetService(); var fileMarker = scope.ServiceProvider.GetService(); + var folderDao = scope.ServiceProvider.GetService>(); + var toFolderId = toFolder.ID; - var isToFolder = Equals(toFolderId.ToString(), _toFolderId); + var isToFolder = Equals(toFolderId, DaoFolderId); + foreach (var folderId in folderIds) { @@ -141,8 +196,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations try { //if destination folder contains folder with same name then merge folders - var conflictFolder = FolderDao.GetFolder(folder.Title, toFolderId); - Folder newFolder; + var conflictFolder = folderDao.GetFolder(folder.Title, toFolderId); + Folder newFolder; if (copy || conflictFolder != null) { @@ -151,7 +206,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations newFolder = conflictFolder; if (isToFolder) - _needToMark.Add(conflictFolder); + needToMark.Add(conflictFolder); } else { @@ -159,11 +214,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations filesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderCopied, newFolder.Title, toFolder.Title); if (isToFolder) - _needToMark.Add(newFolder); + needToMark.Add(newFolder); if (ProcessedFolder(folderId)) { - Status += string.Format("folder_{0}{1}", newFolder.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", newFolder.ID, SPLIT_CHAR); } } @@ -183,7 +238,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations FolderDao.DeleteFolder(folder.ID); if (ProcessedFolder(folderId)) { - Status += string.Format("folder_{0}{1}", newFolder.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", newFolder.ID, SPLIT_CHAR); } } } @@ -192,7 +247,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { if (conflictFolder != null) { - T newFolderId; + TTo newFolderId; if (copy) { newFolder = FolderDao.CopyFolder(folder.ID, toFolderId, CancellationToken); @@ -200,11 +255,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations filesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderCopiedWithOverwriting, newFolder.Title, toFolder.Title); if (isToFolder) - _needToMark.Add(newFolder); + needToMark.Add(newFolder); if (ProcessedFolder(folderId)) { - Status += string.Format("folder_{0}{1}", newFolderId, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR); } } else if (!FilesSecurity.CanDelete(folder)) @@ -220,15 +275,23 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations fileMarker.RemoveMarkAsNewForAll(folder); newFolderId = FolderDao.MoveFolder(folder.ID, toFolderId, CancellationToken); - newFolder = FolderDao.GetFolder(newFolderId); - filesMessageService.Send(folder.RootFolderType != FolderType.USER ? folder : newFolder, toFolder, _headers, MessageAction.FolderMovedWithOverwriting, folder.Title, toFolder.Title); + newFolder = folderDao.GetFolder(newFolderId); + + if (folder.RootFolderType != FolderType.USER) + { + filesMessageService.Send(folder, toFolder, _headers, MessageAction.FolderMovedWithOverwriting, folder.Title, toFolder.Title); + } + else + { + filesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderMovedWithOverwriting, folder.Title, toFolder.Title); + } if (isToFolder) - _needToMark.Add(newFolder); + needToMark.Add(newFolder); if (ProcessedFolder(folderId)) { - Status += string.Format("folder_{0}{1}", newFolderId, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR); } } } @@ -249,15 +312,23 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations fileMarker.RemoveMarkAsNewForAll(folder); var newFolderId = FolderDao.MoveFolder(folder.ID, toFolderId, CancellationToken); - newFolder = FolderDao.GetFolder(newFolderId); - filesMessageService.Send(folder.RootFolderType != FolderType.USER ? folder : newFolder, toFolder, _headers, MessageAction.FolderMoved, folder.Title, toFolder.Title); + newFolder = folderDao.GetFolder(newFolderId); + + if (folder.RootFolderType != FolderType.USER) + { + filesMessageService.Send(folder, toFolder, _headers, MessageAction.FolderMoved, folder.Title, toFolder.Title); + } + else + { + filesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderMoved, folder.Title, toFolder.Title); + } if (isToFolder) - _needToMark.Add(newFolder); + needToMark.Add(newFolder); if (ProcessedFolder(folderId)) { - Status += string.Format("folder_{0}{1}", newFolderId, FileOperation.SPLIT_CHAR); + Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR); } } } @@ -271,17 +342,22 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } ProgressStep(FolderDao.CanCalculateSubitems(folderId) ? default : folderId); } + + return needToMark; } - private void MoveOrCopyFiles(IServiceScope scope, List fileIds, Folder toFolder, bool copy) + private List> MoveOrCopyFiles(IServiceScope scope, List fileIds, Folder toFolder, bool copy) { - if (fileIds.Count == 0) return; + var needToMark = new List>(); + + if (fileIds.Count == 0) return needToMark; var filesMessageService = scope.ServiceProvider.GetService(); var fileMarker = scope.ServiceProvider.GetService(); var fileUtility = scope.ServiceProvider.GetService(); var global = scope.ServiceProvider.GetService(); var entryManager = scope.ServiceProvider.GetService(); + var fileDao = scope.ServiceProvider.GetService>(); var toFolderId = toFolder.ID; foreach (var fileId in fileIds) @@ -309,10 +385,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { var conflict = _resolveType == FileConflictResolveType.Duplicate ? null - : FileDao.GetFile(toFolderId, file.Title); + : fileDao.GetFile(toFolderId, file.Title); if (conflict == null) { - File newFile = null; + File newFile = null; if (copy) { try @@ -320,21 +396,21 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations newFile = FileDao.CopyFile(file.ID, toFolderId); //Stream copy will occur inside dao filesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileCopied, newFile.Title, parentFolder.Title, toFolder.Title); - if (Equals(newFile.FolderID.ToString(), _toFolderId)) + if (Equals(newFile.FolderID.ToString(), DaoFolderId)) { - _needToMark.Add(newFile); + needToMark.Add(newFile); } if (ProcessedFile(fileId)) { - Status += string.Format("file_{0}{1}", newFile.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR); } } catch { if (newFile != null) { - FileDao.DeleteFile(newFile.ID); + fileDao.DeleteFile(newFile.ID); } throw; } @@ -350,17 +426,25 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations fileMarker.RemoveMarkAsNewForAll(file); var newFileId = FileDao.MoveFile(file.ID, toFolderId); - newFile = FileDao.GetFile(newFileId); - filesMessageService.Send(file.RootFolderType != FolderType.USER ? file : newFile, toFolder, _headers, MessageAction.FileMoved, file.Title, parentFolder.Title, toFolder.Title); + newFile = fileDao.GetFile(newFileId); - if (Equals(toFolderId.ToString(), _toFolderId)) + if (file.RootFolderType != FolderType.USER) { - _needToMark.Add(newFile); + filesMessageService.Send(file, toFolder, _headers, MessageAction.FileMoved, file.Title, parentFolder.Title, toFolder.Title); + } + else + { + filesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileMoved, file.Title, parentFolder.Title, toFolder.Title); + } + + if (Equals(toFolderId.ToString(), DaoFolderId)) + { + needToMark.Add(newFile); } if (ProcessedFile(fileId)) { - Status += string.Format("file_{0}{1}", newFileId, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", newFileId, SPLIT_CHAR); } } } @@ -395,17 +479,17 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { newFile.ContentLength = stream.CanSeek ? stream.Length : file.ContentLength; - newFile = FileDao.SaveFile(newFile, stream); + newFile = fileDao.SaveFile(newFile, stream); } - _needToMark.Add(newFile); + needToMark.Add(newFile); if (copy) { filesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileCopiedWithOverwriting, newFile.Title, parentFolder.Title, toFolder.Title); if (ProcessedFile(fileId)) { - Status += string.Format("file_{0}{1}", newFile.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR); } } else @@ -414,7 +498,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { if (ProcessedFile(fileId)) { - Status += string.Format("file_{0}{1}", newFile.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR); } } else @@ -427,11 +511,18 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { FileDao.DeleteFile(file.ID); - filesMessageService.Send(file.RootFolderType != FolderType.USER ? file : newFile, toFolder, _headers, MessageAction.FileMovedWithOverwriting, file.Title, parentFolder.Title, toFolder.Title); + if (file.RootFolderType != FolderType.USER) + { + filesMessageService.Send(file, toFolder, _headers, MessageAction.FileMovedWithOverwriting, file.Title, parentFolder.Title, toFolder.Title); + } + else + { + filesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileMovedWithOverwriting, file.Title, parentFolder.Title, toFolder.Title); + } if (ProcessedFile(fileId)) { - Status += string.Format("file_{0}{1}", newFile.ID, FileOperation.SPLIT_CHAR); + Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR); } } } @@ -452,6 +543,8 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? default : fileId); } + + return needToMark; } private bool WithError(IServiceScope scope, IEnumerable> files, out string error) diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index b0979f83e6..6400bffb20 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -189,9 +189,28 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } successProcessed = thirdpartyTask.GetProperty(PROCESSED) + daoTask.GetProperty(PROCESSED); - processed = (thirdpartyTask.GetProperty(PROGRESS) + daoTask.GetProperty(PROGRESS)) / 2; + base.FillDistributedTask(); + + var progress = 0; + + if (ThirdPartyOperation.Total != 0) + { + progress += thirdpartyTask.GetProperty(PROGRESS); + } + + if (DaoOperation.Total != 0) + { + progress += daoTask.GetProperty(PROGRESS); + } + + if (ThirdPartyOperation.Total != 0 && DaoOperation.Total != 0) + { + progress /= 2; + } + + TaskInfo.SetProperty(PROGRESS, progress < 100 ? progress : 100); TaskInfo.PublishChanges(); } @@ -211,10 +230,10 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations public bool HoldResult { get; set; } - protected FileOperationData(List folders, List files, Tenant tenant, bool holdResult = true) + protected FileOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, bool holdResult = true) { - Folders = folders ?? new List(); - Files = files ?? new List(); + Folders = folders?.ToList() ?? new List(); + Files = files?.ToList() ?? new List(); Tenant = tenant; HoldResult = holdResult; } @@ -251,6 +270,11 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Folders = fileOperationData.Folders; HoldResult = fileOperationData.HoldResult; CurrentTenant = fileOperationData.Tenant; + + using var scope = ServiceProvider.CreateScope(); + var daoFactory = scope.ServiceProvider.GetService(); + FolderDao = daoFactory.GetFolderDao(); + Total = InitTotalProgressSteps(); Source = string.Join(SPLIT_CHAR, Folders.Select(f => "folder_" + f).Concat(Files.Select(f => "file_" + f)).ToArray()); } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index 2522b0d0fb..84351b2d83 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -118,24 +118,28 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations var op = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders, files, tenantManager.GetCurrentTenant(), headers)); return QueueTask(authContext, op); - } + } + + public ItemList MoveOrCopy(AuthContext authContext, TenantManager tenantManager, IEnumerable folders, IEnumerable files, object destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) + { + var tenant = tenantManager.GetCurrentTenant(); + var op1 = new FileMoveCopyOperation(ServiceProvider, new FileMoveCopyOperationData(folders.OfType().Select(Convert.ToInt32), files.OfType().Select(Convert.ToInt32), tenant, destFolderId, copy, resolveType, holdResult, headers)); + var op2 = new FileMoveCopyOperation(ServiceProvider, new FileMoveCopyOperationData(folders, files, tenant, destFolderId, copy, resolveType, holdResult, headers)); + var op = new FileMoveCopyOperation(ServiceProvider, op2, op1); - public ItemList MoveOrCopy(AuthContext authContext, TenantManager tenantManager, List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) - { - var op = new FileMoveCopyOperation(ServiceProvider, new FileMoveCopyOperationData(folders, files, tenantManager.GetCurrentTenant(), destFolderId, copy, resolveType, holdResult, headers)); return QueueTask(authContext, op); } - public ItemList Delete(AuthContext authContext, TenantManager tenantManager, List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + public ItemList Delete(AuthContext authContext, TenantManager tenantManager, IEnumerable folders, IEnumerable files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) { var op = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders, files, tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); return QueueTask(authContext, op); } - public ItemList Delete(AuthContext authContext, TenantManager tenantManager, List folders, List files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) + public ItemList Delete(AuthContext authContext, TenantManager tenantManager, IEnumerable folders, IEnumerable files, bool ignoreException, bool holdResult, bool immediately, Dictionary headers) { - var op1 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders.OfType().Select(Convert.ToInt32).ToList(), files.OfType().Select(Convert.ToInt32).ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); - var op2 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders.OfType().ToList(), files.OfType().ToList(), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); + var op1 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders.OfType().Select(Convert.ToInt32), files.OfType().Select(Convert.ToInt32), tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); + var op2 = new FileDeleteOperation(ServiceProvider, new FileDeleteOperationData(folders, files, tenantManager.GetCurrentTenant(), holdResult, ignoreException, immediately, headers)); var op = new FileDeleteOperation(ServiceProvider, op2, op1); return QueueTask(authContext, op); @@ -191,7 +195,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return FileOperationsManager.Download(AuthContext, TenantManager, folders, files, headers); } - public ItemList MoveOrCopy(List folders, List files, T destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) + public ItemList MoveOrCopy(IEnumerable folders, IEnumerable files, object destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary headers) { return FileOperationsManager.MoveOrCopy(AuthContext, TenantManager, folders, files, destFolderId, copy, resolveType, holdResult, headers); } diff --git a/products/ASC.Files/Server/ThirdPartyApp/Token.cs b/products/ASC.Files/Server/ThirdPartyApp/Token.cs index a98ed94cdb..9d4dea1fc8 100644 --- a/products/ASC.Files/Server/ThirdPartyApp/Token.cs +++ b/products/ASC.Files/Server/ThirdPartyApp/Token.cs @@ -159,7 +159,7 @@ namespace ASC.Web.Files.ThirdPartyApp private OAuth20Token DecryptToken(string token) { - return string.IsNullOrEmpty(token) ? null : Token.FromJson(InstanceCrypto.Decrypt(token)); + return string.IsNullOrEmpty(token) ? null : OAuth20Token.FromJson(InstanceCrypto.Decrypt(token)); } } From b62bdc6938d4867730274792e5fa73e5701105fa Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 25 Mar 2020 11:08:31 +0300 Subject: [PATCH 26/30] Files: MarkAsRead operation --- .../Server/Controllers/FilesController.cs | 11 ++--------- .../Server/Core/FileStorageService.cs | 10 ++++------ .../GoogleDrive/GoogleDriveProviderInfo.cs | 2 +- .../Server/Helpers/FilesControllerHelper.cs | 9 ++------- .../FileOperations/FileMarkAsReadOperation.cs | 19 ++++++++++++++++++- .../FileOperations/FileOperationsManager.cs | 11 +++++++---- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 939e3eb185..161182a6ce 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -263,7 +263,7 @@ namespace ASC.Api.Documents return FilesControllerHelperString.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders).NotFoundIfNull(); } - [Read("{folderId:int}", order: int.MaxValue)] + [Read("{folderId:int}", order: int.MaxValue - 1)] public FolderContentWrapper GetFolder(int folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { return FilesControllerHelperInt.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders); @@ -948,18 +948,11 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/markasread")] - public IEnumerable MarkAsRead(BaseBatchModel model) + public IEnumerable MarkAsRead(BaseBatchModel model) { return FilesControllerHelperString.MarkAsRead(model); } - [Update("fileops/markasread")] - [BodySpecific] - public IEnumerable MarkAsRead(BaseBatchModel model) - { - return FilesControllerHelperInt.MarkAsRead(model); - } - /// /// Finishes all the active file operations /// diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index 6c24c73a1d..ba888078c6 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -1039,9 +1039,9 @@ namespace ASC.Web.Files.Services.WCFService result = new List(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false))); - if (!result.ToList().Any()) + if (!result.Any()) { - MarkAsRead(new ItemList { "folder_" + folderId }); + MarkAsRead(new List() { folderId }, new List() { }); } var response = new HttpResponseMessage(HttpStatusCode.OK) @@ -1057,11 +1057,9 @@ namespace ASC.Web.Files.Services.WCFService } } - public ItemList MarkAsRead(ItemList items) + public ItemList MarkAsRead(IEnumerable foldersId, IEnumerable filesId) { - if (items.Count == 0) return GetTasksStatuses(); - - ParseArrayItems(items, out var foldersId, out var filesId); + if (!foldersId.Any() && !filesId.Any()) return GetTasksStatuses(); return FileOperationsManagerHelper.MarkAsRead(foldersId, filesId); } diff --git a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index 01d493e5d4..3309868f48 100644 --- a/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Server/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -106,7 +106,7 @@ namespace ASC.Files.Thirdparty.GoogleDrive } } - public GoogleDriveStorageDisposableWrapper Wrapper { get; } + public GoogleDriveStorageDisposableWrapper Wrapper { get; set; } public GoogleDriveProviderInfoHelper GoogleDriveProviderInfoHelper { get; } public ILog Log { get; } diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index 9714155318..34a76edd86 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -444,14 +444,9 @@ namespace ASC.Files.Helpers .Select(FileOperationWraperHelper.Get); } - public IEnumerable MarkAsRead(BaseBatchModel model) + public IEnumerable MarkAsRead(BaseBatchModel model) { - var itemList = new ItemList(); - - itemList.AddRange((model.FolderIds ?? new List()).Select(x => "folder_" + x)); - itemList.AddRange((model.FileIds ?? new List()).Select(x => "file_" + x)); - - return FileStorageService.MarkAsRead(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.MarkAsRead(model.FolderIds, model.FileIds).Select(FileOperationWraperHelper.Get); } public IEnumerable TerminateTasks() diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs index 534380ef8e..ab880f4ba1 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileMarkAsReadOperation.cs @@ -40,9 +40,26 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations { class FileMarkAsReadOperationData : FileOperationData { - public FileMarkAsReadOperationData(List folders, List files, Tenant tenant, bool holdResult = true) : base(folders, files, tenant, holdResult) + public FileMarkAsReadOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, bool holdResult = true) + : this(folders.OfType(), files.OfType(), tenant, holdResult) { } + public FileMarkAsReadOperationData(IEnumerable folders, IEnumerable files, Tenant tenant, bool holdResult = true) : base(folders, files, tenant, holdResult) + { + } + } + + class FileMarkAsReadOperation : ComposeFileOperation, FileMarkAsReadOperationData> + { + public FileMarkAsReadOperation(IServiceProvider serviceProvider, FileOperation, string> f1, FileOperation, int> f2) + : base(serviceProvider, f1, f2) + { + } + + public override FileOperationType OperationType + { + get { return FileOperationType.MarkAsRead; } + } } class FileMarkAsReadOperation : FileOperation, T> diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index 84351b2d83..6f7e241327 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -99,9 +99,12 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } - public ItemList MarkAsRead(AuthContext authContext, TenantManager tenantManager, List folderIds, List fileIds) - { - var op = new FileMarkAsReadOperation(ServiceProvider, new FileMarkAsReadOperationData(folderIds, fileIds, tenantManager.GetCurrentTenant())); + public ItemList MarkAsRead(AuthContext authContext, TenantManager tenantManager, IEnumerable folderIds, IEnumerable fileIds) + { + var tenant = tenantManager.GetCurrentTenant(); + var op1 = new FileMarkAsReadOperation(ServiceProvider, new FileMarkAsReadOperationData(folderIds.OfType().Select(Convert.ToInt32), fileIds.OfType().Select(Convert.ToInt32), tenant)); + var op2 = new FileMarkAsReadOperation(ServiceProvider, new FileMarkAsReadOperationData(folderIds, fileIds, tenant)); + var op = new FileMarkAsReadOperation(ServiceProvider, op2, op1); return QueueTask(authContext, op); } @@ -185,7 +188,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return FileOperationsManager.CancelOperations(AuthContext); } - public ItemList MarkAsRead(List folderIds, List fileIds) + public ItemList MarkAsRead(IEnumerable folderIds, IEnumerable fileIds) { return FileOperationsManager.MarkAsRead(AuthContext, TenantManager, folderIds, fileIds); } From 674ae9b4121efac35ccb4dd38f43f229285d3c53 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 25 Mar 2020 17:04:02 +0300 Subject: [PATCH 27/30] Files: Download operation --- products/ASC.Files/Server/ASC.Files.csproj | 3 +- .../Server/Controllers/FilesController.cs | 11 +- .../Server/Core/FileStorageService.cs | 5 +- .../Server/Helpers/FilesControllerHelper.cs | 19 +- products/ASC.Files/Server/Model/BatchModel.cs | 8 +- .../FileOperations/FileDownloadOperation.cs | 341 ++++++++++-------- .../FileOperations/FileOperation.cs | 8 + .../FileOperations/FileOperationsManager.cs | 12 +- products/ASC.Files/Server/Startup.cs | 4 + 9 files changed, 241 insertions(+), 170 deletions(-) diff --git a/products/ASC.Files/Server/ASC.Files.csproj b/products/ASC.Files/Server/ASC.Files.csproj index 477d868e38..7e4951fcc9 100644 --- a/products/ASC.Files/Server/ASC.Files.csproj +++ b/products/ASC.Files/Server/ASC.Files.csproj @@ -29,7 +29,7 @@ - + @@ -40,6 +40,7 @@ + diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 161182a6ce..8ab5a3a0bb 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -988,18 +988,11 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/bulkdownload")] - public IEnumerable BulkDownload(DownloadModel model) + public IEnumerable BulkDownload(DownloadModel model) { return FilesControllerHelperString.BulkDownload(model); } - [BodySpecific] - [Update("fileops/bulkdownload")] - public IEnumerable BulkDownload(DownloadModel model) - { - return FilesControllerHelperInt.BulkDownload(model); - } - /// /// Deletes the files and folders with the IDs specified in the request /// @@ -1011,7 +1004,7 @@ namespace ASC.Api.Documents /// File operations /// Operation result [Update("fileops/delete")] - public IEnumerable DeleteBatchItems(DeleteBatchModel batch) + public IEnumerable DeleteBatchItems(DeleteBatchModel batch) { return FileStorageService.DeleteItems("delete", batch.FileIds.ToList(), batch.FolderIds.ToList(), false, batch.DeleteAfter, batch.Immediately) .Select(FileOperationWraperHelper.Get); diff --git a/products/ASC.Files/Server/Core/FileStorageService.cs b/products/ASC.Files/Server/Core/FileStorageService.cs index ba888078c6..6c7c921a21 100644 --- a/products/ASC.Files/Server/Core/FileStorageService.cs +++ b/products/ASC.Files/Server/Core/FileStorageService.cs @@ -1260,10 +1260,9 @@ namespace ASC.Web.Files.Services.WCFService return FileOperationsManagerHelper.CancelOperations(); } - public ItemList BulkDownload(Dictionary items) + public ItemList BulkDownload(Dictionary folders, Dictionary files) { - ParseArrayItems(items, out var folders, out var files); - ErrorIf(folders.Count == 0 && files.Count == 0, FilesCommonResource.ErrorMassage_BadRequest); + ErrorIf(!folders.Any() && !files.Any(), FilesCommonResource.ErrorMassage_BadRequest); return FileOperationsManagerHelper.Download(folders, files, GetHttpHeaders()); } diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index 34a76edd86..7095d352a5 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -459,26 +459,27 @@ namespace ASC.Files.Helpers return FileStorageService.GetTasksStatuses().Select(FileOperationWraperHelper.Get); } - public IEnumerable BulkDownload(DownloadModel model) + public IEnumerable BulkDownload(DownloadModel model) { - var itemList = new Dictionary(); + var folders = new Dictionary(); + var files = new Dictionary(); - foreach (var fileId in model.FileConvertIds.Where(fileId => !itemList.ContainsKey(fileId.Key))) + foreach (var fileId in model.FileConvertIds.Where(fileId => !files.ContainsKey(fileId.Key))) { - itemList.Add("file_" + fileId.Key, fileId.Value); + files.Add(fileId.Key, fileId.Value); } - foreach (var fileId in model.FileIds.Where(fileId => !itemList.ContainsKey(fileId.ToString()))) + foreach (var fileId in model.FileIds.Where(fileId => !files.ContainsKey(fileId))) { - itemList.Add("file_" + fileId, string.Empty); + files.Add(fileId, string.Empty); } - foreach (var folderId in model.FolderIds.Where(folderId => !itemList.ContainsKey(folderId.ToString()))) + foreach (var folderId in model.FolderIds.Where(folderId => !folders.ContainsKey(folderId))) { - itemList.Add("folder_" + folderId, string.Empty); + folders.Add(folderId, string.Empty); } - return FileStorageService.BulkDownload(itemList).Select(FileOperationWraperHelper.Get); + return FileStorageService.BulkDownload(folders, files).Select(FileOperationWraperHelper.Get); } public IEnumerable EmptyTrash() diff --git a/products/ASC.Files/Server/Model/BatchModel.cs b/products/ASC.Files/Server/Model/BatchModel.cs index 17a5a949c1..c4b93e2493 100644 --- a/products/ASC.Files/Server/Model/BatchModel.cs +++ b/products/ASC.Files/Server/Model/BatchModel.cs @@ -16,12 +16,16 @@ namespace ASC.Files.Model } } - public class DownloadModel : BaseBatchModel + public class DownloadModel : BaseBatchModel { public IEnumerable> FileConvertIds { get; set; } + public DownloadModel() : base() + { + FileConvertIds = new List>(); + } } - public class DeleteBatchModel : BaseBatchModel + public class DeleteBatchModel : BaseBatchModel { public bool DeleteAfter { get; set; } public bool Immediately { get; set; } diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs index a3b42adc43..37085650c4 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileDownloadOperation.cs @@ -32,6 +32,7 @@ using System.Text; using System.Threading; using ASC.Common.Security.Authentication; +using ASC.Common.Threading; using ASC.Core.Tenants; using ASC.Data.Storage; using ASC.Files.Core; @@ -62,41 +63,38 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } - class FileDownloadOperation : FileOperation, T> + class FileDownloadOperation : ComposeFileOperation, FileDownloadOperationData> { - private readonly Dictionary files; - private readonly Dictionary headers; + public FileDownloadOperation(IServiceProvider serviceProvider, FileOperation, string> f1, FileOperation, int> f2) + : base(serviceProvider, f1, f2) + { + } public override FileOperationType OperationType { get { return FileOperationType.Download; } } - - public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData fileDownloadOperationData) - : base(serviceProvider, fileDownloadOperationData) + public override void RunJob(DistributedTask _, CancellationToken cancellationToken) { - files = fileDownloadOperationData.FilesDownload; - headers = fileDownloadOperationData.Headers; - } - - - protected override void Do(IServiceScope scope) - { - var entriesPathId = GetEntriesPathId(scope); - if (entriesPathId == null || entriesPathId.Count == 0) - { - if (0 < Files.Count) - throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); - throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound); - } + base.RunJob(_, cancellationToken); + using var scope = ThirdPartyOperation.CreateScope(); var globalStore = scope.ServiceProvider.GetService(); var filesLinkUtility = scope.ServiceProvider.GetService(); - ReplaceLongPath(entriesPathId); + using var stream = TempStream.Create(); + using (var zip = new ZipOutputStream(stream, true) + { + CompressionLevel = Ionic.Zlib.CompressionLevel.Level3, + AlternateEncodingUsage = ZipOption.AsNecessary, + AlternateEncoding = Encoding.UTF8, + }) + { + (ThirdPartyOperation as FileDownloadOperation).CompressToZip(zip, stream, scope); + (DaoOperation as FileDownloadOperation).CompressToZip(zip, stream, scope); + } - using var stream = CompressToZip(scope, entriesPathId); if (stream != null) { stream.Position = 0; @@ -111,6 +109,76 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations Status = string.Format("{0}?{1}=bulk", filesLinkUtility.FileHandlerPath, FilesLinkUtility.Action); } } + } + + class FileDownloadOperation : FileOperation, T> + { + private readonly Dictionary files; + private readonly Dictionary headers; + ItemNameValueCollection entriesPathId; + public override FileOperationType OperationType + { + get { return FileOperationType.Download; } + } + + public bool Compress { get; } + + public FileDownloadOperation(IServiceProvider serviceProvider, FileDownloadOperationData fileDownloadOperationData, bool compress = true) + : base(serviceProvider, fileDownloadOperationData) + { + files = fileDownloadOperationData.FilesDownload; + headers = fileDownloadOperationData.Headers; + Compress = compress; + } + + + protected override void Do(IServiceScope scope) + { + if (!Compress && !Files.Any() && !Folders.Any()) return; + + entriesPathId = GetEntriesPathId(scope); + if (entriesPathId == null || entriesPathId.Count == 0) + { + if (Files.Count > 0) + { + throw new FileNotFoundException(FilesCommonResource.ErrorMassage_FileNotFound); + } + + throw new DirectoryNotFoundException(FilesCommonResource.ErrorMassage_FolderNotFound); + } + + var globalStore = scope.ServiceProvider.GetService(); + var filesLinkUtility = scope.ServiceProvider.GetService(); + + ReplaceLongPath(entriesPathId); + + if (Compress) + { + using var stream = TempStream.Create(); + using var zip = new ZipOutputStream(stream, true) + { + CompressionLevel = Ionic.Zlib.CompressionLevel.Level3, + AlternateEncodingUsage = ZipOption.AsNecessary, + AlternateEncoding = Encoding.UTF8 + }; + + CompressToZip(zip, stream, scope); + + if (stream != null) + { + stream.Position = 0; + const string fileName = FileConstant.DownloadTitle + ".zip"; + var store = globalStore.GetStore(); + store.Save( + FileConstant.StorageDomainTmp, + string.Format(@"{0}\{1}", ((IAccount)Thread.CurrentPrincipal.Identity).ID, fileName), + stream, + "application/zip", + "attachment; filename=\"" + fileName + "\""); + Status = string.Format("{0}?{1}=bulk", filesLinkUtility.FileHandlerPath, FilesLinkUtility.Action); + } + } + } private ItemNameValueCollection ExecPathFromFile(IServiceScope scope, File file, string path) { @@ -190,119 +258,109 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return entriesPathId; } - private Stream CompressToZip(IServiceScope scope, ItemNameValueCollection entriesPathId) + internal void CompressToZip(ZipOutputStream zip, Stream stream, IServiceScope scope) { var setupInfo = scope.ServiceProvider.GetService(); var fileConverter = scope.ServiceProvider.GetService(); var filesMessageService = scope.ServiceProvider.GetService(); + var FileDao = scope.ServiceProvider.GetService>(); - var stream = TempStream.Create(); - using (var zip = new ZipOutputStream(stream, true)) + foreach (var path in entriesPathId.AllKeys) { - zip.CompressionLevel = Ionic.Zlib.CompressionLevel.Level3; - zip.AlternateEncodingUsage = ZipOption.AsNecessary; - zip.AlternateEncoding = Encoding.UTF8; - - foreach (var path in entriesPathId.AllKeys) + var counter = 0; + foreach (var entryId in entriesPathId[path]) { - var counter = 0; - foreach (var entryId in entriesPathId[path]) + if (CancellationToken.IsCancellationRequested) { - if (CancellationToken.IsCancellationRequested) + zip.Dispose(); + stream.Dispose(); + CancellationToken.ThrowIfCancellationRequested(); + } + + var newtitle = path; + + File file = null; + var convertToExt = string.Empty; + + if (!entryId.Equals(default(T))) + { + FileDao.InvalidateCache(entryId); + file = FileDao.GetFile(entryId); + + if (file == null) { - zip.Dispose(); - stream.Dispose(); - CancellationToken.ThrowIfCancellationRequested(); + Error = FilesCommonResource.ErrorMassage_FileNotFound; + continue; } - var newtitle = path; + if (file.ContentLength > setupInfo.AvailableFileSize) + { + Error = string.Format(FilesCommonResource.ErrorMassage_FileSizeZip, FileSizeComment.FilesSizeToString(setupInfo.AvailableFileSize)); + continue; + } - File file = null; - var convertToExt = string.Empty; + if (files.ContainsKey(file.ID)) + { + convertToExt = files[file.ID]; + if (!string.IsNullOrEmpty(convertToExt)) + { + newtitle = FileUtility.ReplaceFileExtension(path, convertToExt); + } + } + } + + if (0 < counter) + { + var suffix = " (" + counter + ")"; if (!entryId.Equals(default(T))) { - FileDao.InvalidateCache(entryId); - file = FileDao.GetFile(entryId); + newtitle = 0 < newtitle.IndexOf('.') ? newtitle.Insert(newtitle.LastIndexOf('.'), suffix) : newtitle + suffix; + } + else + { + break; + } + } - if (file == null) - { - Error = FilesCommonResource.ErrorMassage_FileNotFound; - continue; - } + zip.PutNextEntry(newtitle); - if (file.ContentLength > setupInfo.AvailableFileSize) + if (!entryId.Equals(default(T)) && file != null) + { + try + { + if (fileConverter.EnableConvert(file, convertToExt)) { - Error = string.Format(FilesCommonResource.ErrorMassage_FileSizeZip, FileSizeComment.FilesSizeToString(setupInfo.AvailableFileSize)); - continue; - } - - if (files.ContainsKey(file.ID)) - { - convertToExt = files[file.ID]; + //Take from converter + using var readStream = fileConverter.Exec(file, convertToExt); + readStream.StreamCopyTo(zip); if (!string.IsNullOrEmpty(convertToExt)) { - newtitle = FileUtility.ReplaceFileExtension(path, convertToExt); - } - } - } - - if (0 < counter) - { - var suffix = " (" + counter + ")"; - - if (!entryId.Equals(default(T))) - { - newtitle = 0 < newtitle.IndexOf('.') ? newtitle.Insert(newtitle.LastIndexOf('.'), suffix) : newtitle + suffix; - } - else - { - break; - } - } - - zip.PutNextEntry(newtitle); - - if (!entryId.Equals(default(T)) && file != null) - { - try - { - if (fileConverter.EnableConvert(file, convertToExt)) - { - //Take from converter - using (var readStream = fileConverter.Exec(file, convertToExt)) - { - readStream.StreamCopyTo(zip); - if (!string.IsNullOrEmpty(convertToExt)) - { - filesMessageService.Send(file, headers, MessageAction.FileDownloadedAs, file.Title, convertToExt); - } - else - { - filesMessageService.Send(file, headers, MessageAction.FileDownloaded, file.Title); - } - } + filesMessageService.Send(file, headers, MessageAction.FileDownloadedAs, file.Title, convertToExt); } else { - using var readStream = FileDao.GetFileStream(file); - readStream.StreamCopyTo(zip); filesMessageService.Send(file, headers, MessageAction.FileDownloaded, file.Title); } } - catch (Exception ex) + else { - Error = ex.Message; - Logger.Error(Error, ex); + using var readStream = FileDao.GetFileStream(file); + readStream.StreamCopyTo(zip); + filesMessageService.Send(file, headers, MessageAction.FileDownloaded, file.Title); } } - counter++; + catch (Exception ex) + { + Error = ex.Message; + Logger.Error(Error, ex); + } } - - ProgressStep(); + counter++; } + + ProgressStep(); } - return stream; } private void ReplaceLongPath(ItemNameValueCollection entriesPathId) @@ -320,61 +378,60 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations entriesPathId.Add(newtitle, ids); } } + } + + internal class ItemNameValueCollection + { + private readonly Dictionary> dic = new Dictionary>(); - class ItemNameValueCollection + public IEnumerable AllKeys { - private readonly Dictionary> dic = new Dictionary>(); + get { return dic.Keys; } + } + public IEnumerable this[string name] + { + get { return dic[name].ToArray(); } + } - public IEnumerable AllKeys + public int Count + { + get { return dic.Count; } + } + + public void Add(string name, T value) + { + if (!dic.ContainsKey(name)) { - get { return dic.Keys; } + dic.Add(name, new List()); } + dic[name].Add(value); + } - public IEnumerable this[string name] + public void Add(ItemNameValueCollection collection) + { + foreach (var key in collection.AllKeys) { - get { return dic[name].ToArray(); } - } - - public int Count - { - get { return dic.Count; } - } - - public void Add(string name, T value) - { - if (!dic.ContainsKey(name)) + foreach (var value in collection[key]) { - dic.Add(name, new List()); - } - dic[name].Add(value); - } - - public void Add(ItemNameValueCollection collection) - { - foreach (var key in collection.AllKeys) - { - foreach (var value in collection[key]) - { - Add(key, value); - } + Add(key, value); } } + } - public void Add(string name, IEnumerable values) + public void Add(string name, IEnumerable values) + { + if (!dic.ContainsKey(name)) { - if (!dic.ContainsKey(name)) - { - dic.Add(name, new List()); - } - dic[name].AddRange(values); + dic.Add(name, new List()); } + dic[name].AddRange(values); + } - public void Remove(string name) - { - dic.Remove(name); - } + public void Remove(string name) + { + dic.Remove(name); } } } \ No newline at end of file diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs index 6400bffb20..63deb5a423 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperation.cs @@ -334,6 +334,14 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations } } + public IServiceScope CreateScope() + { + var scope = ServiceProvider.CreateScope(); + var tenantManager = scope.ServiceProvider.GetService(); + tenantManager.SetCurrentTenant(CurrentTenant); + return scope; + } + protected internal override void FillDistributedTask() { base.FillDistributedTask(); diff --git a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs index 6f7e241327..8242bb0000 100644 --- a/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs +++ b/products/ASC.Files/Server/Services/WCFService/FileOperations/FileOperationsManager.cs @@ -108,7 +108,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return QueueTask(authContext, op); } - public ItemList Download(AuthContext authContext, TenantManager tenantManager, Dictionary folders, Dictionary files, Dictionary headers) + public ItemList Download(AuthContext authContext, TenantManager tenantManager, Dictionary folders, Dictionary files, Dictionary headers) { var operations = tasks.GetTasks() .Where(t => t.GetProperty(FileOperation.OWNER) == authContext.CurrentAccount.ID) @@ -117,9 +117,13 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations if (operations.Any(o => o.Status <= DistributedTaskStatus.Running)) { throw new InvalidOperationException(FilesCommonResource.ErrorMassage_ManyDownloads); - } + } + + var tenant = tenantManager.GetCurrentTenant(); + var op1 = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders.Where(r => r.Key is long).ToDictionary(r => Convert.ToInt32(r.Key), r => r.Value), files.Where(r => r.Key is long).ToDictionary(r => Convert.ToInt32(r.Key), r => r.Value), tenant, headers), false); + var op2 = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders.Where(r => r.Key is string).ToDictionary(r => r.Key.ToString(), r => r.Value), files.Where(r => r.Key is string).ToDictionary(r => r.Key.ToString(), r => r.Value), tenant, headers), false); + var op = new FileDownloadOperation(ServiceProvider, op2, op1); - var op = new FileDownloadOperation(ServiceProvider, new FileDownloadOperationData(folders, files, tenantManager.GetCurrentTenant(), headers)); return QueueTask(authContext, op); } @@ -193,7 +197,7 @@ namespace ASC.Web.Files.Services.WCFService.FileOperations return FileOperationsManager.MarkAsRead(AuthContext, TenantManager, folderIds, fileIds); } - public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) + public ItemList Download(Dictionary folders, Dictionary files, Dictionary headers) { return FileOperationsManager.Download(AuthContext, TenantManager, folders, files, headers); } diff --git a/products/ASC.Files/Server/Startup.cs b/products/ASC.Files/Server/Startup.cs index 1b7437319d..f26462cac7 100644 --- a/products/ASC.Files/Server/Startup.cs +++ b/products/ASC.Files/Server/Startup.cs @@ -1,4 +1,6 @@ +using System.Text; + using ASC.Api.Core.Auth; using ASC.Api.Core.Core; using ASC.Api.Core.Middleware; @@ -35,6 +37,8 @@ namespace ASC.Files public void ConfigureServices(IServiceCollection services) { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + services.AddHttpContextAccessor(); services.AddControllers() From f4f6ec90546e5a72d8d09b2b40427c69deb6abfb Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Thu, 2 Apr 2020 14:19:38 +0300 Subject: [PATCH 28/30] Files: fixed missing after merge --- products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs index f1ef16aeec..0053a261dd 100644 --- a/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs +++ b/products/ASC.Files/Server/Core/Dao/TeamlabDao/FolderDao.cs @@ -406,9 +406,10 @@ namespace ASC.Files.Core.Data var treeToDelete = FilesDbContext.Tree.Where(r => subfolders.Any(a => r.FolderId == a)); FilesDbContext.Tree.RemoveRange(treeToDelete); - + + var subfoldersStrings = subfolders.Select(r => r.ToString()).ToList(); var linkToDelete = Query(FilesDbContext.TagLink) - .Where(r => subfolders.Any(a => r.EntryId == a)) + .Where(r => subfoldersStrings.Any(a => r.EntryId == a)) .Where(r => r.EntryType == FileEntryType.Folder); FilesDbContext.TagLink.RemoveRange(linkToDelete); @@ -418,7 +419,7 @@ namespace ASC.Files.Core.Data FilesDbContext.Tag.RemoveRange(tagsToRemove); var securityToDelete = Query(FilesDbContext.Security) - .Where(r => subfolders.Any(a => r.EntryId == a)) + .Where(r => subfoldersStrings.Any(a => r.EntryId == a)) .Where(r => r.EntryType == FileEntryType.Folder); FilesDbContext.Security.RemoveRange(securityToDelete); From a9ff1939039388f7f414eb974d8355b9aad68591 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Thu, 2 Apr 2020 14:21:05 +0300 Subject: [PATCH 29/30] Files: fixed property name --- products/ASC.Files/Server/Controllers/FilesController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 8ab5a3a0bb..4c9ce5c5ed 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -198,9 +198,9 @@ namespace ASC.Api.Documents /// Folders /// Projects folder contents [Read("@projects")] - public FolderContentWrapper GetProjectsFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfold) + public FolderContentWrapper GetProjectsFolder(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { - return ToFolderContentWrapper(GlobalFolderHelper.GetFolderProjects(), userIdOrGroupId, filterType, withsubfold); + return ToFolderContentWrapper(GlobalFolderHelper.GetFolderProjects(), userIdOrGroupId, filterType, withsubfolders); } From f96db8dd51c2d14b979f2ccb9e145080370b79ad Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Thu, 2 Apr 2020 15:05:53 +0300 Subject: [PATCH 30/30] Files: added property DisableFormat for string format --- .../Server/Controllers/FilesController.cs | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index 4c9ce5c5ed..282933d204 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -257,7 +257,7 @@ namespace ASC.Api.Documents /// User or group ID /// Filter type /// Folder contents - [Read("{folderId}", order: int.MaxValue)] + [Read("{folderId}", order: int.MaxValue, DisableFormat = true)] public FolderContentWrapper GetFolder(string folderId, Guid userIdOrGroupId, FilterType filterType, bool withsubfolders) { return FilesControllerHelperString.GetFolder(folderId, userIdOrGroupId, filterType, withsubfolders).NotFoundIfNull(); @@ -342,7 +342,7 @@ namespace ASC.Api.Documents /// If True, upload documents in original formats as well /// Keep status conversation after finishing /// Uploaded file - [Create("{folderId}/upload")] + [Create("{folderId}/upload", DisableFormat = true)] public List> UploadFile(string folderId, UploadModel uploadModel) { return FilesControllerHelperString.UploadFile(folderId, uploadModel); @@ -394,7 +394,7 @@ namespace ASC.Api.Documents /// Keep status conversation after finishing /// Uploads /// - [Create("{folderId}/insert")] + [Create("{folderId}/insert", DisableFormat = true)] public FileWrapper InsertFile(string folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false) { return FilesControllerHelperString.InsertFile(folderId, file, title, createNewIfExist, keepConvertStatus); @@ -414,7 +414,7 @@ namespace ASC.Api.Documents /// /// /// false - [Update("{fileId}/update")] + [Update("{fileId}/update", DisableFormat = true)] public FileWrapper UpdateFileStream(Stream file, string fileId, bool encrypted = false) { return FilesControllerHelperString.UpdateFileStream(file, fileId, encrypted); @@ -438,7 +438,7 @@ namespace ASC.Api.Documents /// /// Files /// - [Update("file/{fileId}/saveediting")] + [Update("file/{fileId}/saveediting", DisableFormat = true)] public FileWrapper SaveEditing(string fileId, string fileExtension, string downloadUri, Stream stream, string doc, bool forcesave) { return FilesControllerHelperString.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave); @@ -458,7 +458,7 @@ namespace ASC.Api.Documents /// /// Files /// - [Create("file/{fileId}/startedit")] + [Create("file/{fileId}/startedit", DisableFormat = true)] public string StartEdit(string fileId, bool editingAlone, string doc) { return FilesControllerHelperString.StartEdit(fileId, editingAlone, doc); @@ -480,7 +480,7 @@ namespace ASC.Api.Documents /// /// Files /// - [Read("file/{fileId}/trackeditfile")] + [Read("file/{fileId}/trackeditfile", DisableFormat = true)] public KeyValuePair TrackEditFile(string fileId, Guid tabId, string docKeyForTrack, string doc, bool isFinish) { return FilesControllerHelperString.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish); @@ -500,7 +500,7 @@ namespace ASC.Api.Documents /// /// Files /// - [Read("file/{fileId}/openedit")] + [Read("file/{fileId}/openedit", DisableFormat = true)] public Configuration OpenEdit(string fileId, int version, string doc) { return FilesControllerHelperString.OpenEdit(fileId, version, doc); @@ -545,7 +545,7 @@ namespace ASC.Api.Documents /// /// ]]> /// - [Create("{folderId}/upload/create_session")] + [Create("{folderId}/upload/create_session", DisableFormat = true)] public object CreateUploadSession(string folderId, string fileName, long fileSize, string relativePath, bool encrypted) { return FilesControllerHelperString.CreateUploadSession(folderId, fileName, fileSize, relativePath, encrypted); @@ -594,7 +594,7 @@ namespace ASC.Api.Documents /// File title /// File contents /// Folder contents - [Create("{folderId}/text")] + [Create("{folderId}/text", DisableFormat = true)] public FileWrapper CreateTextFile(string folderId, string title, string content) { return FilesControllerHelperString.CreateTextFile(folderId, title, content); @@ -615,7 +615,7 @@ namespace ASC.Api.Documents /// File title /// File contents /// Folder contents - [Create("{folderId}/html")] + [Create("{folderId}/html", DisableFormat = true)] public FileWrapper CreateHtmlFile(string folderId, string title, string content) { return FilesControllerHelperString.CreateHtmlFile(folderId, title, content); @@ -667,7 +667,7 @@ namespace ASC.Api.Documents /// Parent folder ID /// Title of new folder /// New folder contents - [Create("folder/{folderId}")] + [Create("folder/{folderId}", DisableFormat = true)] public FolderWrapper CreateFolder(string folderId, string title) { return FilesControllerHelperString.CreateFolder(folderId, title); @@ -703,7 +703,7 @@ namespace ASC.Api.Documents /// 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 - [Create("{folderId}/file")] + [Create("{folderId}/file", DisableFormat = true)] public FileWrapper CreateFile(string folderId, string title) { return FilesControllerHelperString.CreateFile(folderId, title); @@ -725,7 +725,7 @@ namespace ASC.Api.Documents /// Folder ID /// New title /// Folder contents - [Update("folder/{folderId}")] + [Update("folder/{folderId}", DisableFormat = true)] public FolderWrapper RenameFolder(string folderId, string title) { return FilesControllerHelperString.RenameFolder(folderId, title); @@ -743,7 +743,7 @@ namespace ASC.Api.Documents /// Folder information /// Folders /// Folder info - [Read("folder/{folderId}")] + [Read("folder/{folderId}", DisableFormat = true)] public FolderWrapper GetFolderInfo(string folderId) { return FilesControllerHelperString.GetFolderInfo(folderId); @@ -761,7 +761,7 @@ namespace ASC.Api.Documents /// /// Folders /// Parent folders - [Read("folder/{folderId}/path")] + [Read("folder/{folderId}/path", DisableFormat = true)] public IEnumerable> GetFolderPath(string folderId) { return FilesControllerHelperString.GetFolderPath(folderId); @@ -800,7 +800,7 @@ namespace ASC.Api.Documents /// New title /// File last version number /// File info - [Update("file/{fileId}")] + [Update("file/{fileId}", DisableFormat = true)] public FileWrapper UpdateFile(string fileId, string title, int lastVersion) { return FilesControllerHelperString.UpdateFile(fileId, title, lastVersion); @@ -821,7 +821,7 @@ namespace ASC.Api.Documents /// Delete after finished /// Don't move to the Recycle Bin /// Operation result - [Delete("file/{fileId}")] + [Delete("file/{fileId}", DisableFormat = true)] public IEnumerable DeleteFile(string fileId, bool deleteAfter, bool immediately) { return FilesControllerHelperString.DeleteFile(fileId, deleteAfter, immediately); @@ -840,7 +840,7 @@ namespace ASC.Api.Documents /// File operations /// /// Operation result - [Update("file/{fileId}/checkconversion")] + [Update("file/{fileId}/checkconversion", DisableFormat = true)] public IEnumerable> StartConversion(string fileId) { return FilesControllerHelperString.StartConversion(fileId); @@ -860,7 +860,7 @@ namespace ASC.Api.Documents /// /// /// Operation result - [Read("file/{fileId}/checkconversion")] + [Read("file/{fileId}/checkconversion", DisableFormat = true)] public IEnumerable> CheckConversion(string fileId, bool start) { return FilesControllerHelperString.CheckConversion(fileId, start); @@ -881,7 +881,7 @@ namespace ASC.Api.Documents /// Delete after finished /// Don't move to the Recycle Bin /// Operation result - [Delete("folder/{folderId}")] + [Delete("folder/{folderId}", DisableFormat = true)] public IEnumerable DeleteFolder(string folderId, bool deleteAfter, bool immediately) { return FilesControllerHelperString.DeleteFolder(folderId, deleteAfter, immediately); @@ -1029,7 +1029,7 @@ namespace ASC.Api.Documents /// Files /// File ID /// File information - [Read("file/{fileId}/history")] + [Read("file/{fileId}/history", DisableFormat = true)] public IEnumerable> GetFileVersionInfo(string fileId) { return FilesControllerHelperString.GetFileVersionInfo(fileId); @@ -1049,7 +1049,7 @@ namespace ASC.Api.Documents /// Mark as version or revision /// Files /// - [Update("file/{fileId}/history")] + [Update("file/{fileId}/history", DisableFormat = true)] public IEnumerable> ChangeHistory(string fileId, int version, bool continueVersion) { return FilesControllerHelperString.ChangeHistory(fileId, version, continueVersion); @@ -1067,7 +1067,7 @@ namespace ASC.Api.Documents /// Sharing /// File ID /// Shared file information - [Read("file/{fileId}/share")] + [Read("file/{fileId}/share", DisableFormat = true)] public IEnumerable GetFileSecurityInfo(string fileId) { return FilesControllerHelperString.GetFileSecurityInfo(fileId); @@ -1086,7 +1086,7 @@ namespace ASC.Api.Documents /// Folder ID /// Sharing /// Shared folder information - [Read("folder/{folderId}/share")] + [Read("folder/{folderId}/share", DisableFormat = true)] public IEnumerable GetFolderSecurityInfo(string folderId) { return FilesControllerHelperString.GetFolderSecurityInfo(folderId); @@ -1111,7 +1111,7 @@ namespace ASC.Api.Documents /// Each of the FileShareParams must contain two parameters: 'ShareTo' - ID of the user with whom we want to share and 'Access' - access type which we want to grant to the user (Read, ReadWrite, etc) /// /// Shared file information - [Update("file/{fileId}/share")] + [Update("file/{fileId}/share", DisableFormat = true)] public IEnumerable SetFileSecurityInfo(string fileId, IEnumerable share, bool notify, string sharingMessage) { return FilesControllerHelperString.SetFileSecurityInfo(fileId, share, notify, sharingMessage); @@ -1136,7 +1136,7 @@ namespace ASC.Api.Documents /// /// Sharing /// Shared folder information - [Update("folder/{folderId}/share")] + [Update("folder/{folderId}/share", DisableFormat = true)] public IEnumerable SetFolderSecurityInfo(string folderId, IEnumerable share, bool notify, string sharingMessage) { return FilesControllerHelperString.SetFolderSecurityInfo(folderId, share, notify, sharingMessage); @@ -1178,7 +1178,7 @@ namespace ASC.Api.Documents /// Access right /// Files /// Shared file link - [Update("{fileId}/sharedlink")] + [Update("{fileId}/sharedlink", DisableFormat = true)] public string GenerateSharedLink(string fileId, FileShare share) { return FilesControllerHelperString.GenerateSharedLink(fileId, share);