using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.FileProviders; using xCommons.Constants; using xCommons.Extensions; using xExceptions.Constants; using xModels.Dtos; using xStorageService.Constants; using xStorageService.Helpers; using xStorageService.Interfaces; using xStorageService.Models; namespace xStorageService.Providers { public partial class XStorageProvider : IXStorageProvider { public readonly string BasePath; private readonly XFileType[] ThumbSupprtedTypes = new XFileType[] { XFileType.Image, XFileType.CoverImage, XFileType.ProfileImasge }; public IFileProvider FileProvider { get; } public XStorageHelper StorageHelper { get; } public IXThumbnailProvider ThumbnailProvider { get; } public XStorageConfiguration Configuration { get; } public XStorageProvider ( IFileProvider fileProvider, XStorageHelper storageHelper, IXThumbnailProvider thumbnailProvider, XStorageConfiguration configuration ) { // FileProvider = fileProvider; Configuration = configuration; StorageHelper = storageHelper; ThumbnailProvider = thumbnailProvider; // BasePath = Path .Combine (Directory .GetCurrentDirectory (), Configuration.BaseFolder); } // #region Special Folders Path Getter (s) ... /// /// Get Storage Folder Path /// /// public string GetStorageFolderPath () { return Path.Combine (BasePath, Configuration.Storage); } /// /// Get Temp Folder Path /// /// public string GetTempFolderPath () { return Path.Combine (GetStorageFolderPath (), Configuration.Temp); } /// /// Get Uploads Folder Path /// /// public string GetUploadsFolderPath () { return Path.Combine (GetStorageFolderPath (), Configuration.Uploads); } /// /// Get Widgets Folder Path /// /// public string GetWidgetsFolderPath () { return Path.Combine (GetStorageFolderPath (), Configuration.Widgets); } /// /// Get Thumb Folder Path /// /// public string GetThumbFolderPath () { return Path.Combine (GetUploadsFolderPath (), Configuration.Thumb); } /// /// Get Images Folder Path /// /// public string GetImageFolderPath () { return Path.Combine (GetUploadsFolderPath (), Configuration.Image); } /// /// Get Audios Folder Path /// /// public string GetAudioFolderPath () { return Path.Combine (GetUploadsFolderPath (), Configuration.Audio); } /// /// Get Videos Folder Path /// /// public string GetVideoFolderPath () { return Path.Combine (GetUploadsFolderPath (), Configuration.Video); } /// /// Get Documents Folder Path /// /// public string GetDocumentFolderPath () { return Path.Combine (GetUploadsFolderPath (), Configuration.Document); } /// /// Prepare Full Path to Use for Static Files /// /// /// public string FilePathResolver (string fullPath) { return fullPath.Replace (BasePath, ""); } /// /// Convert a File Path to Url /// /// /// public string ConvertToProfileImageUrl (string fullPath) { // var authority = !Configuration.IdentityAuthority.IsNullOrEmpty () && Configuration.IdentityAuthority.EndsWith ("/") ? Configuration.IdentityAuthority.Substring (0, Configuration.IdentityAuthority.Length - 1) : Configuration.IdentityAuthority; // return $"{authority}{FilePathResolver(fullPath)}"; } /// /// Convert a File Path to Url /// /// /// public string ConvertToFileUrl (string fullPath) { // var authority = !Configuration.Authority.IsNullOrEmpty () && Configuration.Authority.EndsWith ("/") ? Configuration.Authority.Substring (0, Configuration.Authority.Length - 1) : Configuration.Authority; // return $"{authority}/{FilePathResolver(fullPath)}"; } #endregion // #region Prepare Storage Structure ... /// /// Check Folder Structure of Storage Area /// and Create them if not Exists /// public void Prepare () { // try { // // Storage Folder Path Check ... if (!IsFolderExists (GetStorageFolderPath ())) { Directory.CreateDirectory (GetStorageFolderPath ()); } // // Temp Folder Path Check ... if (!IsFolderExists (GetTempFolderPath ())) { Directory.CreateDirectory (GetTempFolderPath ()); } // // Temp Folder Path Check ... if (!IsFolderExists (GetThumbFolderPath ())) { Directory.CreateDirectory (GetThumbFolderPath ()); } // // Widgets Folder Path Chekc ... if (!IsFolderExists (GetWidgetsFolderPath ())) { Directory.CreateDirectory (GetWidgetsFolderPath ()); } // // Uploads Folder Path Chekc ... if (!IsFolderExists (GetUploadsFolderPath ())) { Directory.CreateDirectory (GetUploadsFolderPath ()); } // // Image Folder Path Chekc ... if (!IsFolderExists (GetImageFolderPath ())) { Directory.CreateDirectory (GetImageFolderPath ()); } // // Music Folder Path Chekc ... if (!IsFolderExists (GetAudioFolderPath ())) { Directory.CreateDirectory (GetAudioFolderPath ()); } // // Video Folder Path Chekc ... if (!IsFolderExists (GetVideoFolderPath ())) { Directory.CreateDirectory (GetVideoFolderPath ()); } // // Document Folder Path Chekc ... if (!IsFolderExists (GetDocumentFolderPath ())) { Directory.CreateDirectory (GetDocumentFolderPath ()); } } catch { XException.StorageServiceInitialFailed.Throw (); } // // Set Temp Folder for Actions ... ThumbnailProvider.SetTempFolder (GetTempFolderPath ()); } #endregion // #region Validators ... /// /// Detrmines a Path Exists or not /// /// /// public bool IsFolderExists (string path) { return Directory.Exists (path); } /// /// Check a File Exists or not /// /// /// public bool IsFileExists (string filePath) { return File.Exists (filePath); } /// /// Check a File Name Support Thumbnail or not /// /// /// public bool IsSupportThumb (string fileName) { // if (!fileName.StartsWith (Configuration.FilePrefix)) { XException.InavlidFile.Throw (); } // var fileType = StorageHelper.GetType (fileName); return IsSupportThumb (fileType); } /// /// Check a FileType Support Thumbnail or not /// /// /// public bool IsSupportThumb (XFileType type) { return ThumbSupprtedTypes.Contains (type); } /// /// Validate a File Exists or not /// /// public void ValidateFileExists (string filePath) { // if (!IsFileExists (filePath)) { XException.NotFound.Throw (); } } /// /// Validate a File Model with it's Related Physical File /// /// public void ValidateFileModel (XFileDto file) { // // Validate Args ... if (file == null) { XException.InvalidArgs.Throw (); } // // Retrieve Full File Path ... var fileFullPath = file.Path; if (fileFullPath.IsNullOrEmpty ()) { XException.InavlidFile.Throw (); } // // Retrieve is File Exists or not ... var isPhysicalFileExists = IsFileExists (file.Path); if (!isPhysicalFileExists) { XException.NotFound.Throw (); } } /// /// Validate File for Upload /// /// public void ValidateFile (IFormFile file) { // // Validate Args ... if (file == null) { XException.InvalidArgs.Throw (); } // // Check File Size not Zero ... if (file.Length == 0) { XException.EmptyFile.Throw (); } // // Check File Max Size ... if (file.Length > Configuration.MaxFileSize) { XException.MaxFileSizeExceeded.Throw (); } } /// /// Validate a Collection of IFormFile /// /// public void ValidateFiles (IFormFileCollection files) { // // Validate Args ... if (!files.HasChild ()) { XException.InvalidArgs.Throw (); } // files.ToList () .ForEach (f => ValidateFile (f)); } /// /// Validate File for Profile Image /// /// public void ValidateProfileImage (IFormFile file) { // // Check File Validation ... // since Args Checked in File Validation, there is no need to // double check it ... ValidateFile (file); // // Check File Type ... var fileType = GetFileType (file.FileName); if (fileType != XFileType.Image) { XException.UnsupportedFileType.Throw (); } } #endregion // #region Generators ... /// /// Generate New File /// /// public string NewFileName () { return Configuration.FilePrefix + Guid.NewGuid ().ToString ().ToLower (); } /// /// Retrieve Related Thumnail File /// /// /// public string GenerateThumbName (string fileName) { // if (!IsSupportThumb (fileName)) { XException.UnsupportedFileType.Throw (); } // return fileName.Replace (Configuration.FilePrefix, Configuration.ThumbPrefix); } /// /// Get a New FileName with Extension based on Given fileName /// /// /// public string GetNewFileName (string fileName) { // // Validate Args ... if (fileName.IsNullOrEmpty ()) { XException.InvalidArgs.Throw (); } // var fileExt = GetFileExtension (fileName); var newFileNameWithoutExt = NewFileName (); // // Generate New File Name ... var newFileName = string.Format ("{0}{1}", newFileNameWithoutExt, fileExt); // return newFileName; } #endregion // #region Tools Actions ... /// /// Extract a FileName's Extension /// /// /// public string GetFileExtension (string fileName) { // var result = StorageHelper.GetFileExtension (fileName); if (result.IsNullOrEmpty ()) { XException.InvalidArgs.Throw (); } // return result; } /// /// Extract a FileName's Without it's Extension /// /// /// public string GetFileNameWithoutExtension (string fileName) { // var result = StorageHelper.GetFileNameWithoutExtension (fileName); if (result.IsNullOrEmpty ()) { XException.InvalidArgs.Throw (); } // return result; } /// /// Get file Extension of Specified File Name /// /// /// public FileExtensions GetFileExtensionType (string fileName) { // var fileExt = GetFileExtension (fileName); if (fileExt.IsNullOrEmpty ()) { XException.InvalidData.Throw (); } // var result = StorageHelper.GetExtensionType (fileExt); if (result == -1) { XException.UnsupportedFileType.Throw (); } // return (FileExtensions) result; } /// /// Return File Type of Specific File Name /// /// /// public XFileType GetFileType (string fileName) { // var fileExtension = GetFileExtensionType (fileName); return GetFileType (fileExtension); } /// /// Return File Type of Specific Extension /// /// /// public XFileType GetFileType (FileExtensions fileExtension) { return StorageHelper.GetType ((int) fileExtension); } /// /// Retrieve Full Path of thumbnail File /// /// /// public string GetThumbnailFileFullPath (string thumFileName) { // if (!thumFileName.StartsWith (Configuration.ThumbPrefix)) { XException.InavlidFile.Throw (); } // return Path.Combine (GetThumbFolderPath (), thumFileName); } /// /// Retrieve a File Thumbnail Path if Supported /// /// /// public string GetRelatedThumbnailFullPath (string fileName) { // var thumbName = GenerateThumbName (fileName); return GetThumbnailFileFullPath (thumbName); } /// /// Retrieve Special File Type's Folder Path /// /// /// public string GetFileTypeFolderPath (XFileType type) { // // Retrieve Folder Path Based on file ... switch (type) { case XFileType.Image: case XFileType.CoverImage: case XFileType.ProfileImasge: return GetImageFolderPath (); case XFileType.Audio: return GetAudioFolderPath (); case XFileType.Video: return GetVideoFolderPath (); case XFileType.Document: default: return GetDocumentFolderPath (); } } /// /// Retrieve a File's Folder path /// /// /// /// /// public string GetFileFolderPath ( string fileName, bool isTemp = false, bool isWidget = false) { // // Validate Args ... if (fileName.IsNullOrEmpty ()) { XException.InvalidArgs.Throw (); } // var fileType = GetFileType (fileName); // var folderPath = ""; // // if isTemp equals true // ignore file type and return Temp Folder ... if (isTemp) { folderPath = GetTempFolderPath (); } // // if isWidget equals true and isTemp equals false // ignore file type and return Widget's Folder ... if (isWidget && !isTemp) { folderPath = GetWidgetsFolderPath (); } // // if both isTemp and isWidget equals false // which is the default state, retrieve proper folder path // based on file type and return it ... if (!isTemp && !isWidget) { folderPath = GetFileTypeFolderPath (fileType); } // // Check folderPath restrict to have Value ... if (folderPath.IsNullOrEmpty ()) { XException.InvalidData.Throw (); } // // return result ... return folderPath; } /// /// Retrieve a Full path of a File /// /// /// /// /// public string GetFileFullPath ( string fileName, bool isTemp = false, bool isWidget = false ) { // var folderPath = GetFileFolderPath ( fileName, isTemp : isTemp, isWidget : isWidget ); // if (folderPath.IsNullOrEmpty ()) { XException.ActionFailed.Throw (); } // return Path.Combine (folderPath, fileName); } /// /// Save a File into Storage Based on it's Type /// /// /// public async Task SaveFileAsync ( IFormFile file, bool isTemp = false, bool isWidget = false) { // // Validate Args ... ValidateFile (file); // // Extract and Generate required Data ... var fileName = GetNewFileName (file.FileName); var folderPath = GetFileFolderPath (file.FileName, isTemp, isWidget); var fileFullPath = Path.Combine (folderPath, fileName); // // Save File ... using (var stream = new FileStream (fileFullPath, FileMode.Create)) { await file.CopyToAsync (stream); } // // Since all Required data can be Generated based on // a simple file Name, there is no need to return additional // data as result ... return fileName; } /// /// Delete a Physical File by Validate it's Exists /// /// public void DeleteFile ( string fileFullPath, bool forceFileExists = true, Exception exception = null) { // // Validate Args ... if (!forceFileExists && fileFullPath.IsNullOrEmpty ()) { XException.InvalidArgs.Throw (); } // // Prepare Default Exception ... if (exception == null) { exception = XException.NotFound.ToException (); } // // Check File Exists ... var isFileExists = File.Exists (fileFullPath); if (forceFileExists && !isFileExists) { XException.NotFound.Throw (); } // // Handle Prevent Error when forceFileExists false // and File doesn't Exists ... if (!forceFileExists && !isFileExists) { return; } // File.Delete (fileFullPath); } /// /// Remove a List of Physical Files Path /// and return Un Removable Files ... /// /// /// /// /// public ICollection DeleteFiles ( ICollection fileFullPaths, bool forceFileExists = true, Exception exception = null ) { // if (exception.IsNull ()) { exception = XException.NotFound.ToException (); } // var result = fileFullPaths.Where (f => !IsFileExists (GetFileFullPath (f))).ToList (); if (forceFileExists && result.HasChild ()) { throw exception; } // var existsFile = fileFullPaths.Where (f => IsFileExists (f)).ToList (); existsFile.ForEach (f => { DeleteFile ( f, forceFileExists : forceFileExists, exception : exception ); }); // return fileFullPaths.Except (existsFile).ToList (); } /// /// Create Thumbnail based on FileName.Ext /// /// /// public async Task CreateThumbnail (string fileName) { // if (fileName.IsNullOrEmpty ()) { return; } // await Task.Run (() => { // var fileFullPath = GetFileFullPath (fileName); if (!IsFileExists (fileFullPath)) { XException.NotFound.Throw (); } // var thumbFileName = GenerateThumbName (fileName); var thumbFullPath = GetThumbnailFileFullPath (thumbFileName); // ThumbnailProvider.ResizeImage ( fileFullPath, thumbFullPath, Configuration.ThumbSize, Configuration.ThumbQuality ); }); } /// /// Create Thumbnail based on XFile model /// /// /// public async Task CreateThumbnail (XFileDto file) { // await CreateThumbnail (file.Name); } // /// // /// Create Thumbnail based on XFile model // /// // /// // /// // public async Task CreateThumbnail (XFile file) { // // // await CreateThumbnail (file.Name); // } /// /// Save and Create a Thumbnail For Profile Image /// /// /// public async Task HandleProfileImageSave (IFormFile file) { // ValidateProfileImage (file); // var savedFileName = await SaveFileAsync (file, isTemp : false, isWidget : false); var thumbFileName = GenerateThumbName (savedFileName); // var savedFileFullPath = GetFileFullPath (savedFileName); var thumbFullPath = GetThumbnailFileFullPath (thumbFileName); // await CreateThumbnail (savedFileName); // return new XFileResult { Name = file.Name, FileName = savedFileName, FilePath = ConvertToProfileImageUrl (savedFileFullPath), Thmbnail = thumbFileName, ThmbnailPath = ConvertToProfileImageUrl (thumbFullPath) }; } /// /// Handle File Upload with Support of Thumbnails ... /// /// /// public async Task HandleFileSave (IFormFile file) { // ValidateFile (file); // var savedFileName = await SaveFileAsync (file, isTemp : false, isWidget : false); // var savedFileFullPath = GetFileFullPath (savedFileName); // var thumbFileName = ""; var thumbFullPath = ""; var fileType = GetFileType (savedFileName); if (fileType.IsImageKind ()) { // thumbFileName = GenerateThumbName (savedFileName); thumbFullPath = GetThumbnailFileFullPath (thumbFileName); // await CreateThumbnail (savedFileName); } // var result = new XFileResult { Name = file.FileName, FileName = savedFileName, FilePath = ConvertToFileUrl (savedFileFullPath), Thmbnail = thumbFileName, ThmbnailPath = ConvertToFileUrl (thumbFullPath), }; // return result; } /// /// Handle File Upload with Support of Thumbnails ... /// /// /// public async Task> HandleFilesSave (IFormFileCollection files) { // ValidateFiles (files); // var result = new Collection (); foreach (var file in files) { // var savedFileName = await SaveFileAsync (file, isTemp : false, isWidget : false); // var savedFileFullPath = GetFileFullPath (savedFileName); // var thumbFileName = ""; var thumbFullPath = ""; var fileType = GetFileType (savedFileName); if (fileType.IsImageKind ()) { // thumbFileName = GenerateThumbName (savedFileName); thumbFullPath = GetThumbnailFileFullPath (thumbFileName); // await CreateThumbnail (savedFileName); } // result.Add ( new XFileResult { Name = file.FileName, FileName = savedFileName, FilePath = ConvertToFileUrl (savedFileFullPath), Thmbnail = thumbFileName, ThmbnailPath = ConvertToFileUrl (thumbFullPath), }); } // return result; } #endregion } }