Esempio n. 1
0
        protected internal virtual bool CheckUniqueFileName(MediaPathData pathData)
        {
            // (perf) First make fast check
            var exists = _fileRepo.Table.Any(x => x.Name == pathData.FileName && x.FolderId == pathData.Folder.Id);

            if (!exists)
            {
                return(false);
            }

            var q = new MediaSearchQuery
            {
                FolderId = pathData.Folder.Id,
                Term     = string.Concat(pathData.FileTitle, "*.", pathData.Extension),
                Deleted  = null
            };

            var query = _searcher.PrepareQuery(q, MediaLoadFlags.AsNoTracking).Select(x => x.Name);
            var files = new HashSet <string>(query.ToList(), StringComparer.CurrentCultureIgnoreCase);

            if (_helper.CheckUniqueFileName(pathData.FileTitle, pathData.Extension, files, out var uniqueName))
            {
                pathData.FileName = uniqueName;
                return(true);
            }

            return(false);
        }
Esempio n. 2
0
 public MediaPathData(MediaPathData pathData)
 {
     Node   = pathData.Node;
     _name  = pathData.FileName;
     _title = pathData._title;
     _ext   = pathData._ext;
     _mime  = pathData._mime;
 }
Esempio n. 3
0
        protected string GetCachedImagePath(int?mediaFileId, MediaPathData data, ProcessImageQuery query = null)
        {
            string result = "";

            // xxxxxxx
            if (mediaFileId.GetValueOrDefault() > 0)
            {
                result = mediaFileId.Value.ToString(IdFormatString);
            }

            //// INFO: (mm) don't include folder id in pathes for now. It results in more complex image cache invalidation code.
            //// xxxxxxx-f
            //if (data.Folder != null)
            //{
            //	result = result.Grow(data.Folder.Id.ToString(CultureInfo.InvariantCulture), "-");
            //}

            // xxxxxxx-f-abc
            result = result.Grow(data.FileTitle, "-");

            if (result.IsEmpty())
            {
                // files without name? No way!
                return(null);
            }

            if (query != null && query.NeedsProcessing())
            {
                // xxxxxxx-f-abc-w100-h100
                result += query.CreateHash();
            }

            if (_mediaSettings.MultipleThumbDirectories && result.Length > MaxDirLength)
            {
                // Get the first four letters of the file name
                // 0001/xxxxxxx-f-abc-w100-h100
                var subDirectoryName = result.Substring(0, MaxDirLength);
                result = subDirectoryName + "/" + result;
            }

            // 0001/xxxxxxx-f-abc-w100-h100.png
            return(result.Grow(data.Extension, "."));
        }
Esempio n. 4
0
        public virtual CachedImage Get(int?mediaFileId, MediaPathData data, ProcessImageQuery query = null)
        {
            Guard.NotNull(data, nameof(data));

            var resultExtension = query?.GetResultExtension();

            if (resultExtension != null)
            {
                data.Extension = resultExtension;
            }

            var imagePath = GetCachedImagePath(mediaFileId, data, query);
            var file      = _fileSystem.GetFile(BuildPath(imagePath));

            var result = new CachedImage(file)
            {
                Path      = imagePath,
                Extension = data.Extension,
                IsRemote  = _fileSystem.IsCloudStorage
            };

            return(result);
        }
Esempio n. 5
0
        public bool TokenizePath(string path, out MediaPathData data)
        {
            data = null;

            if (path.IsEmpty())
            {
                return(false);
            }

            var dir = Path.GetDirectoryName(path);

            if (dir.HasValue())
            {
                var node = _folderService.GetNodeByPath(dir);
                if (node != null)
                {
                    data = new MediaPathData(node, path.Substring(dir.Length + 1));
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 6
0
        private MediaPathData CreateDestinationPathData(MediaFile file, string destinationFileName)
        {
            if (!_helper.TokenizePath(destinationFileName, true, out var pathData))
            {
                // Passed path is NOT a path, but a file name

                if (IsPath(destinationFileName))
                {
                    // ...but file name includes path chars, which is not allowed
                    throw new ArgumentException(
                              T("Admin.Media.Exception.InvalidPath", Path.GetDirectoryName(destinationFileName)),
                              nameof(destinationFileName));
                }

                if (file.FolderId == null)
                {
                    throw new NotSupportedException(T("Admin.Media.Exception.FolderAssignment"));
                }

                pathData = new MediaPathData(_folderService.GetNodeById(file.FolderId.Value), destinationFileName);
            }

            return(pathData);
        }
        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;
                }
            }
        }
Esempio n. 8
0
        private bool ValidateMoveOperation(
            MediaFile file,
            string destinationFileName,
            DuplicateFileHandling dupeFileHandling,
            out bool nameChanged,
            out MediaPathData destPathData)
        {
            Guard.NotNull(file, nameof(file));
            Guard.NotEmpty(destinationFileName, nameof(destinationFileName));

            destPathData = CreateDestinationPathData(file, destinationFileName);

            var destFileName  = destPathData.FileName;
            var destFolderId  = destPathData.Folder.Id;
            var folderChanged = destFolderId != file.FolderId;
            var shouldRestore = false;

            nameChanged = !destFileName.IsCaseInsensitiveEqual(file.Name);

            if (file.FolderId.HasValue && folderChanged)
            {
                // When "Move" operation: ensure file stays in source album.
                ValidateAlbums("Move", file.FolderId.Value, destFolderId);
            }

            if (nameChanged)
            {
                // Ensure both MIME types are equal
                ValidateMimeTypes("Move", file.MimeType, destPathData.MimeType);
            }

            // Check whether destination file exists
            if (!folderChanged && file.Deleted)
            {
                // Special case where a file is moved from trash to its origin location.
                // In this case the file should just be restored without any dupe check.
                shouldRestore = true;
            }
            else
            {
                var dupe = _fileRepo.Table.FirstOrDefault(x => x.Name == destFileName && x.FolderId == destFolderId);
                if (dupe != null)
                {
                    if (!folderChanged)
                    {
                        throw _exceptionFactory.IdenticalPaths(ConvertMediaFile(file, destPathData.Folder));
                    }

                    switch (dupeFileHandling)
                    {
                    case DuplicateFileHandling.ThrowError:
                        var fullPath = destPathData.FullPath;
                        _helper.CheckUniqueFileName(destPathData.FileTitle, destPathData.Extension, dupe.Name, out _);
                        throw _exceptionFactory.DuplicateFile(fullPath, ConvertMediaFile(dupe, destPathData.Folder), destPathData.FullPath);

                    case DuplicateFileHandling.Rename:
                        if (_helper.CheckUniqueFileName(destPathData.FileTitle, destPathData.Extension, dupe.Name, out var uniqueName))
                        {
                            nameChanged           = true;
                            destPathData.FileName = uniqueName;
                            return(true);
                        }
                        break;

                    case DuplicateFileHandling.Overwrite:
                        DeleteFile(dupe, true);
                        break;
                    }
                }
            }

            return(folderChanged || nameChanged || shouldRestore);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        protected MediaStorageItem ProcessFile(
            ref MediaFile file,
            MediaPathData pathData,
            Stream inStream,
            bool isTransient = true,
            DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError,
            MimeValidationType mediaValidationType = MimeValidationType.MimeTypeMustMatch)
        {
            if (file != null)
            {
                if (dupeFileHandling == DuplicateFileHandling.ThrowError)
                {
                    var fullPath = pathData.FullPath;
                    CheckUniqueFileName(pathData);
                    throw _exceptionFactory.DuplicateFile(fullPath, ConvertMediaFile(file, pathData.Folder), pathData.FullPath);
                }
                else if (dupeFileHandling == DuplicateFileHandling.Rename)
                {
                    if (CheckUniqueFileName(pathData))
                    {
                        file = null;
                    }
                }
            }

            if (file != null && mediaValidationType != MimeValidationType.NoValidation)
            {
                if (mediaValidationType == MimeValidationType.MimeTypeMustMatch)
                {
                    ValidateMimeTypes("Save", file.MimeType, pathData.MimeType);
                }
                else if (mediaValidationType == MimeValidationType.MediaTypeMustMatch)
                {
                    ValidateMediaTypes("Save", _typeResolver.Resolve(pathData.Extension), file.MediaType);
                }

                // Restore file if soft-deleted
                file.Deleted = false;

                // Delete thumbnail
                _imageCache.Delete(file);
            }

            file = file ?? new MediaFile
            {
                IsTransient = isTransient,
                FolderId    = pathData.Node.Value.Id
            };

            // Untrackable folders can never contain transient files.
            if (!pathData.Folder.CanDetectTracks)
            {
                file.IsTransient = false;
            }

            var name = pathData.FileName;

            if (name != pathData.FileName)
            {
                pathData.FileName = name;
            }

            file.Name      = pathData.FileName;
            file.Extension = pathData.Extension;
            file.MimeType  = pathData.MimeType;
            if (file.MediaType == null)
            {
                file.MediaType = _typeResolver.Resolve(pathData.Extension, pathData.MimeType);
            }

            // Process image
            if (inStream != null && inStream.Length > 0 && file.MediaType == MediaType.Image && ProcessImage(file, inStream, out var outImage))
            {
                file.Width     = outImage.Size.Width;
                file.Height    = outImage.Size.Height;
                file.PixelSize = outImage.Size.Width * outImage.Size.Height;

                return(MediaStorageItem.FromImage(outImage));
            }
            else
            {
                file.RefreshMetadata(inStream);

                return(MediaStorageItem.FromStream(inStream));
            }
        }