Beispiel #1
0
        public MediaFileInfo MoveFile(MediaFile file, string destinationFileName, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            if (ValidateMoveOperation(file, destinationFileName, dupeFileHandling, out var nameChanged, out var destPathData))
            {
                file.FolderId = destPathData.Folder.Id;

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

                if (nameChanged)
                {
                    var title = destPathData.FileTitle;
                    var ext   = destPathData.Extension.ToLower();

                    file.Name = title + "." + ext;

                    if (ext != file.Extension.ToLower())
                    {
                        _storageProvider.ChangeExtension(file, ext);
                        file.Extension = ext;
                    }

                    _imageCache.Delete(file);
                }

                _fileRepo.Update(file);
            }

            return(ConvertMediaFile(file, destPathData.Folder));
        }
Beispiel #2
0
        private async Task <(bool Valid, bool NameChanged, MediaPathData DestPathData)> ValidateMoveOperation(
            MediaFile file,
            string destinationFileName,
            DuplicateFileHandling dupeFileHandling)
        {
            Guard.NotNull(file, nameof(file));
            Guard.NotEmpty(destinationFileName, nameof(destinationFileName));

            var destPathData  = CreateDestinationPathData(file, destinationFileName);
            var destFileName  = destPathData.FileName;
            var destFolderId  = destPathData.Folder.Id;
            var folderChanged = destFolderId != file.FolderId;
            var shouldRestore = false;

            var nameChanged = !destFileName.EqualsNoCase(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 = await _db.MediaFiles.FirstOrDefaultAsync(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, nameChanged, destPathData);
                        }
                        break;

                    case DuplicateFileHandling.Overwrite:
                        await DeleteFileAsync(dupe, true);

                        break;
                    }
                }
            }

            return(folderChanged || nameChanged || shouldRestore, nameChanged, destPathData);
        }
Beispiel #3
0
        public async Task <MediaFileInfo> MoveFileAsync(MediaFile file, string destinationFileName, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            var moveOperation = await ValidateMoveOperation(file, destinationFileName, dupeFileHandling);

            var destPathData = moveOperation.DestPathData;
            var nameChanged  = moveOperation.NameChanged;

            if (moveOperation.Valid)
            {
                file.FolderId = destPathData.Folder.Id;

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

                if (nameChanged)
                {
                    var title = destPathData.FileTitle;
                    var ext   = destPathData.Extension.ToLower();

                    file.Name = title + "." + ext;

                    if (ext != file.Extension.ToLower())
                    {
                        await _storageProvider.ChangeExtensionAsync(file, ext);

                        file.Extension = ext;
                    }

                    await _imageCache.DeleteAsync(file);
                }

                _db.TryUpdate(file);
                await _db.SaveChangesAsync();
            }

            return(ConvertMediaFile(file, destPathData.Folder));
        }
Beispiel #4
0
        public async Task <FileOperationResult> CopyFileAsync(MediaFileInfo mediaFile, string destinationFileName, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            Guard.NotNull(mediaFile, nameof(mediaFile));
            Guard.NotEmpty(destinationFileName, nameof(destinationFileName));

            var destPathData = CreateDestinationPathData(mediaFile.File, destinationFileName);
            var destFileName = destPathData.FileName;
            var destFolderId = destPathData.Folder.Id;

            var dupe = mediaFile.FolderId == destPathData.Folder.Id
                       // Source folder equals dest folder, so same file
                ? mediaFile.File
                       // Another dest folder, check for duplicate by file name
                : await _db.MediaFiles.FirstOrDefaultAsync(x => x.Name == destFileName && x.FolderId == destFolderId);

            var copyResult = await InternalCopyFile(
                mediaFile.File,
                destPathData,
                true /* copyData */,
                (DuplicateEntryHandling)((int)dupeFileHandling),
                () => Task.FromResult(dupe),
                p => CheckUniqueFileName(p));

            return(new FileOperationResult
            {
                Operation = "copy",
                DuplicateFileHandling = dupeFileHandling,
                SourceFile = mediaFile,
                DestinationFile = ConvertMediaFile(copyResult.Copy, destPathData.Folder),
                IsDuplicate = copyResult.IsDupe,
                UniquePath = copyResult.IsDupe ? destPathData.FullPath : null
            });
        }
Beispiel #5
0
        protected async Task <(MediaStorageItem StorageItem, MediaFile File)> ProcessFile(
            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;
                    await CheckUniqueFileName(pathData);

                    throw _exceptionFactory.DuplicateFile(fullPath, ConvertMediaFile(file, pathData.Folder), pathData.FullPath);
                }
                else if (dupeFileHandling == DuplicateFileHandling.Rename)
                {
                    if (await 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
                await _imageCache.DeleteAsync(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 && (await ProcessImage(file, inStream)).Out(out var outImage))
            {
                file.Width     = outImage.Width;
                file.Height    = outImage.Height;
                file.PixelSize = outImage.Width * outImage.Height;

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

                return(MediaStorageItem.FromStream(inStream), file);
            }
        }
Beispiel #6
0
        public async Task <MediaFileInfo> SaveFileAsync(string path, Stream stream, bool isTransient = true, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            var pathData = CreatePathData(path);

            var file = await _db.MediaFiles.FirstOrDefaultAsync(x => x.Name == pathData.FileName && x.FolderId == pathData.Folder.Id);

            var isNewFile = file == null;
            var result    = await ProcessFile(file, pathData, stream, isTransient, dupeFileHandling);

            file = result.File;

            if (file.Id == 0)
            {
                _db.MediaFiles.Add(file);
                await _db.SaveChangesAsync();
            }

            try
            {
                await _storageProvider.SaveAsync(file, result.StorageItem);
            }
            catch (Exception ex)
            {
                if (isNewFile)
                {
                    // New file's metadata should be removed on storage save failure immediately
                    await DeleteFileAsync(file, true, true);

                    await _db.SaveChangesAsync();
                }

                Logger.Error(ex);
            }

            return(ConvertMediaFile(file, pathData.Folder));
        }
Beispiel #7
0
        public async Task <ActionResult> Upload(
            string path,
            string[] typeFilter = null,
            bool isTransient    = false,
            DuplicateFileHandling duplicateFileHandling = DuplicateFileHandling.ThrowError,
            string directory = "")
        {
            var numFiles = Request.Form.Files.Count;
            var result   = new List <object>(numFiles);

            for (var i = 0; i < numFiles; ++i)
            {
                if (directory.HasValue())
                {
                    path = _mediaService.CombinePaths(path, directory);

                    if (!_mediaService.FolderExists(path))
                    {
                        await _mediaService.CreateFolderAsync(path);
                    }
                }

                var uploadedFile = Request.Form.Files[i];
                var fileName     = uploadedFile.FileName;
                var filePath     = _mediaService.CombinePaths(path, fileName);

                try
                {
                    // Check if media type or file extension is allowed.
                    var extension = Path.GetExtension(fileName).TrimStart('.').ToLower();
                    if (typeFilter != null)
                    {
                        var mediaTypeExtensions = _mediaTypeResolver.ParseTypeFilter(typeFilter);
                        if (!mediaTypeExtensions.Contains(extension))
                        {
                            throw _exceptionFactory.DeniedMediaType(fileName, extension, typeFilter);
                        }
                    }
                    else
                    {
                        // Check if extension is allowed by media settings.
                        if (!_mediaTypeResolver.GetExtensionMediaTypeMap().Keys.Contains(extension))
                        {
                            throw _exceptionFactory.DeniedMediaType(fileName, extension);
                        }
                    }

                    using var stream = uploadedFile.OpenReadStream();
                    var mediaFile = await _mediaService.SaveFileAsync(filePath, stream, isTransient, duplicateFileHandling);

                    dynamic o = JObject.FromObject(mediaFile);
                    o.success     = true;
                    o.createdOn   = mediaFile.CreatedOn.ToString();
                    o.lastUpdated = mediaFile.LastModified.ToString();

                    result.Add(o);
                }
                catch (DuplicateMediaFileException dex)
                {
                    var dupe = dex.File;

                    dynamic o = JObject.FromObject(dupe);
                    o.dupe       = true;
                    o.errMessage = dex.Message;

                    var newPath = await _mediaService.CheckUniqueFileNameAsync(filePath);

                    o.uniquePath  = newPath;
                    o.createdOn   = dupe.CreatedOn.ToString();
                    o.lastUpdated = dupe.LastModified.ToString();

                    result.Add(o);
                }
                catch (Exception)
                {
                    throw;
                }
            }

            return(Json(result.Count == 1 ? result[0] : result));
        }
Beispiel #8
0
        public FileOperationResult CopyFile(MediaFileInfo mediaFile, string destinationFileName, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            Guard.NotNull(mediaFile, nameof(mediaFile));
            Guard.NotEmpty(destinationFileName, nameof(destinationFileName));

            var destPathData = CreateDestinationPathData(mediaFile.File, destinationFileName);
            var destFileName = destPathData.FileName;
            var destFolderId = destPathData.Folder.Id;

            var dupe = mediaFile.FolderId == destPathData.Folder.Id
                       // Source folder equals dest folder, so same file
                ? mediaFile.File
                       // Another dest folder, check for duplicate by file name
                : _fileRepo.Table.FirstOrDefault(x => x.Name == destFileName && x.FolderId == destFolderId);

            var copy = InternalCopyFile(
                mediaFile.File,
                destPathData,
                true /* copyData */,
                (DuplicateEntryHandling)((int)dupeFileHandling),
                () => dupe,
                p => CheckUniqueFileName(p),
                out var isDupe);

            return(new FileOperationResult
            {
                Operation = "copy",
                DuplicateFileHandling = dupeFileHandling,
                SourceFile = mediaFile,
                DestinationFile = ConvertMediaFile(copy, destPathData.Folder),
                IsDuplicate = isDupe,
                UniquePath = isDupe ? destPathData.FullPath : (string)null
            });
        }
Beispiel #9
0
        public async Task <MediaFileInfo> SaveFileAsync(string path, Stream stream, bool isTransient = true, DuplicateFileHandling dupeFileHandling = DuplicateFileHandling.ThrowError)
        {
            var pathData = CreatePathData(path);

            var file = await _fileRepo.Table.FirstOrDefaultAsync(x => x.Name == pathData.FileName && x.FolderId == pathData.Folder.Id);

            var isNewFile   = file == null;
            var storageItem = ProcessFile(ref file, pathData, stream, isTransient, dupeFileHandling);

            using (var scope = new DbContextScope(_fileRepo.Context, autoCommit: false))
            {
                if (file.Id == 0)
                {
                    _fileRepo.Insert(file);
                    await scope.CommitAsync();
                }

                try
                {
                    await _storageProvider.SaveAsync(file, storageItem);

                    await scope.CommitAsync();
                }
                catch (Exception ex)
                {
                    if (isNewFile)
                    {
                        // New file's metadata should be removed on storage save failure immediately
                        DeleteFile(file, true, true);
                        await scope.CommitAsync();
                    }

                    Logger.Error(ex);
                }
            }

            return(ConvertMediaFile(file, pathData.Folder));
        }