コード例 #1
0
        public async Task <FolderOperationResult> CopyFolderAsync(
            string path,
            string destinationPath,
            DuplicateEntryHandling dupeEntryHandling = DuplicateEntryHandling.Skip,
            CancellationToken cancelToken            = default)
        {
            Guard.NotEmpty(path, nameof(path));
            Guard.NotEmpty(destinationPath, nameof(destinationPath));

            path = FolderService.NormalizePath(path);
            ValidateFolderPath(path, "CopyFolder", nameof(path));

            destinationPath = FolderService.NormalizePath(destinationPath);
            if (destinationPath.EnsureEndsWith("/").StartsWith(path.EnsureEndsWith("/")))
            {
                throw new ArgumentException(T("Admin.Media.Exception.DescendantFolder", destinationPath, path), nameof(destinationPath));
            }

            var node = _folderService.GetNodeByPath(path);

            if (node == null)
            {
                throw _exceptionFactory.FolderNotFound(path);
            }

            if (node.Value.IsAlbum)
            {
                throw new NotSupportedException(T("Admin.Media.Exception.CopyRootAlbum", node.Value.Name));
            }

            using (var scope = new DbContextScope(_db, autoDetectChanges: false, deferCommit: true))
            {
                destinationPath += "/" + node.Value.Name;
                var dupeFiles = new List <DuplicateFileInfo>();

                // >>>> Do the heavy stuff
                var folder = await InternalCopyFolder(scope, node, destinationPath, dupeEntryHandling, dupeFiles, cancelToken);

                var result = new FolderOperationResult
                {
                    Operation = "copy",
                    DuplicateEntryHandling = dupeEntryHandling,
                    Folder         = folder,
                    DuplicateFiles = dupeFiles
                };

                return(result);
            }
        }
コード例 #2
0
ファイル: MediaService.cs プロジェクト: webtrad3r/Smartstore
        private async Task <(MediaFile Copy, bool IsDupe)> InternalCopyFile(
            MediaFile file,
            MediaPathData destPathData,
            bool copyData,
            DuplicateEntryHandling dupeEntryHandling,
            Func <Task <MediaFile> > dupeFileSelector,
            Func <MediaPathData, Task> uniqueFileNameChecker)
        {
            // Find dupe and handle
            var isDupe = false;

            var dupe = await dupeFileSelector();

            if (dupe != null)
            {
                switch (dupeEntryHandling)
                {
                case DuplicateEntryHandling.Skip:
                    await uniqueFileNameChecker(destPathData);

                    return(dupe, true);

                case DuplicateEntryHandling.ThrowError:
                    var fullPath = destPathData.FullPath;
                    await uniqueFileNameChecker(destPathData);

                    throw _exceptionFactory.DuplicateFile(fullPath, ConvertMediaFile(dupe), destPathData.FullPath);

                case DuplicateEntryHandling.Rename:
                    await uniqueFileNameChecker(destPathData);

                    dupe = null;
                    break;

                case DuplicateEntryHandling.Overwrite:
                    if (file.FolderId == destPathData.Folder.Id)
                    {
                        throw new IOException(T("Admin.Media.Exception.Overwrite"));
                    }
                    break;
                }
            }

            isDupe = dupe != null;
            var copy = dupe ?? new MediaFile();

            // Simple clone
            MapMediaFile(file, copy);

            // Set folder id
            copy.FolderId = destPathData.Folder.Id;

            // A copied file cannot stay in deleted state
            copy.Deleted = false;

            // Set name stuff
            if (!copy.Name.EqualsNoCase(destPathData.FileName))
            {
                copy.Name      = destPathData.FileName;
                copy.Extension = destPathData.Extension;
                copy.MimeType  = destPathData.MimeType;
            }

            // Save to DB
            if (isDupe)
            {
                _db.TryUpdate(copy);
            }
            else
            {
                _db.MediaFiles.Add(copy);
            }

            // Copy data: blob, alt, title etc.
            if (copyData)
            {
                await InternalCopyFileData(file, copy);
            }

            return(copy, isDupe);
        }
コード例 #3
0
        private MediaFolderInfo InternalCopyFolder(TreeNode <MediaFolderNode> sourceNode, string destPath, DuplicateEntryHandling dupeEntryHandling, IList <DuplicateFileInfo> dupeFiles)
        {
            // Get dest node
            var destNode = _folderService.GetNodeByPath(destPath);

            // Dupe handling
            if (destNode != null && dupeEntryHandling == DuplicateEntryHandling.ThrowError)
            {
                throw _exceptionFactory.DuplicateFolder(sourceNode.Value.Path, destNode.Value);
            }

            var doDupeCheck = destNode != null;

            // Create dest folder
            if (destNode == null)
            {
                destNode = CreateFolder(destPath);
            }

            var ctx = _fileRepo.Context;

            // INFO: we gonna change file name during the files loop later.
            var destPathData = new MediaPathData(destNode, "placeholder.txt");

            // Get all source files in one go
            var files = _searcher.SearchFiles(
                new MediaSearchQuery {
                FolderId = sourceNode.Value.Id
            },
                MediaLoadFlags.AsNoTracking | MediaLoadFlags.WithTags).Load();

            IDictionary <string, MediaFile> destFiles = null;
            HashSet <string> destNames = null;

            if (doDupeCheck)
            {
                // Get all files in destination folder for faster dupe selection
                destFiles = _searcher.SearchFiles(new MediaSearchQuery {
                    FolderId = destNode.Value.Id
                }, MediaLoadFlags.None).ToDictionarySafe(x => x.Name);

                // Make a HashSet from all file names in the destination folder for faster unique file name lookups
                destNames = new HashSet <string>(destFiles.Keys, StringComparer.CurrentCultureIgnoreCase);
            }

            // Holds source and copy together, 'cause we perform a two-pass copy (file first, then data)
            var tuples = new List <(MediaFile, MediaFile)>(500);

            // Copy files batched
            foreach (var batch in files.Slice(500))
            {
                foreach (var file in batch)
                {
                    destPathData.FileName = file.Name;

                    // >>> Do copy
                    var copy = InternalCopyFile(
                        file,
                        destPathData,
                        false /* copyData */,
                        dupeEntryHandling,
                        () => destFiles?.Get(file.Name),
                        UniqueFileNameChecker,
                        out var isDupe);

                    if (copy != null)
                    {
                        if (isDupe)
                        {
                            dupeFiles.Add(new DuplicateFileInfo
                            {
                                SourceFile      = ConvertMediaFile(file, sourceNode.Value),
                                DestinationFile = ConvertMediaFile(copy, destNode.Value),
                                UniquePath      = destPathData.FullPath
                            });
                        }
                        if (!isDupe || dupeEntryHandling != DuplicateEntryHandling.Skip)
                        {
                            // When dupe: add to processing queue only if file was NOT skipped
                            tuples.Add((file, copy));
                        }
                    }
                }

                // Save batch to DB (1st pass)
                ctx.SaveChanges();

                // Now copy file data
                foreach (var op in tuples)
                {
                    InternalCopyFileData(op.Item1, op.Item2);
                }

                // Save batch to DB (2nd pass)
                ctx.SaveChanges();

                ctx.DetachEntities <MediaFolder>();
                ctx.DetachEntities <MediaFile>();
                tuples.Clear();
            }

            // Copy folders
            foreach (var node in sourceNode.Children)
            {
                destPath = destNode.Value.Path + "/" + node.Value.Name;
                InternalCopyFolder(node, destPath, dupeEntryHandling, dupeFiles);
            }

            return(new MediaFolderInfo(destNode));

            void UniqueFileNameChecker(MediaPathData pathData)
            {
                if (destNames != null && _helper.CheckUniqueFileName(pathData.FileTitle, pathData.Extension, destNames, out var uniqueName))
                {
                    pathData.FileName = uniqueName;
                }
            }
        }
コード例 #4
0
ファイル: MediaService.cs プロジェクト: krreddy123/appcode
        private MediaFile InternalCopyFile(
            MediaFile file,
            MediaPathData destPathData,
            bool copyData,
            DuplicateEntryHandling dupeEntryHandling,
            Func <MediaFile> dupeFileSelector,
            Action <MediaPathData> uniqueFileNameChecker,
            out bool isDupe)
        {
            // Find dupe and handle
            isDupe = false;
            var dupe = dupeFileSelector();

            if (dupe != null)
            {
                switch (dupeEntryHandling)
                {
                case DuplicateEntryHandling.Skip:
                    isDupe = true;
                    uniqueFileNameChecker(destPathData);
                    return(dupe);

                case DuplicateEntryHandling.ThrowError:
                    var fullPath = destPathData.FullPath;
                    uniqueFileNameChecker(destPathData);
                    throw _exceptionFactory.DuplicateFile(fullPath, ConvertMediaFile(dupe), destPathData.FullPath);

                case DuplicateEntryHandling.Rename:
                    uniqueFileNameChecker(destPathData);
                    dupe = null;
                    break;

                case DuplicateEntryHandling.Overwrite:
                    if (file.FolderId == destPathData.Folder.Id)
                    {
                        throw new IOException(T("Admin.Media.Exception.Overwrite"));
                    }
                    break;
                }
            }

            isDupe = dupe != null;
            var copy = dupe ?? new MediaFile();

            // Simple clone
            MapMediaFile(file, copy);

            // Set folder id
            copy.FolderId = destPathData.Folder.Id;

            // A copied file cannot stay in deleted state
            copy.Deleted = false;

            // Set name stuff
            if (!copy.Name.IsCaseInsensitiveEqual(destPathData.FileName))
            {
                copy.Name      = destPathData.FileName;
                copy.Extension = destPathData.Extension;
                copy.MimeType  = destPathData.MimeType;
            }

            // Save to DB
            if (isDupe)
            {
                _fileRepo.Update(copy);
            }
            else
            {
                _fileRepo.Insert(copy);
            }

            // Copy data: blob, alt, title etc.
            if (copyData)
            {
                InternalCopyFileData(file, copy);
            }

            return(copy);
        }