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)); }
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); }
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)); }
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 }); }
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); } }
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)); }
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)); }
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 }); }
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)); }