@namespace Oqtane.Modules.Controls @using System.Threading @inherits ModuleControlBase @inject IFolderService FolderService @inject IFileService FileService @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer @if (_folders != null) {
@if (ShowFolders) {
} @if (ShowFiles) {
} @if (ShowUpload && _haseditpermission) {
@if (UploadMultiple) { } else { }
@if (ShowFiles && GetFileId() != -1) { }
}
@if (_image != string.Empty) {
@((MarkupString) _image)
}
@if (!string.IsNullOrEmpty(_message)) {
}
} @code { private List _folders; private List _files = new List(); private string _fileinputid = string.Empty; private string _progressinfoid = string.Empty; private string _progressbarid = string.Empty; private string _filter = "*"; private bool _haseditpermission = false; private string _image = string.Empty; private File _file = null; private string _guid; private string _message = string.Empty; private MessageType _messagetype; [Parameter] public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility [Parameter] public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid [Parameter] public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path [Parameter] public int FileId { get; set; } = -1; // optional - for selecting a specific file by default [Parameter] public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif" [Parameter] public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true [Parameter] public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true [Parameter] public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true [Parameter] public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true [Parameter] public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false [Parameter] public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false [Parameter] public EventCallback OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded [Parameter] public EventCallback OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected [Parameter] public EventCallback OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted protected override async Task OnInitializedAsync() { // packages folder is a framework folder for uploading installable nuget packages if (Folder == Constants.PackagesFolder) { ShowFiles = false; ShowFolders = false; Filter = "nupkg"; ShowSuccess = true; } if (!ShowFiles) { ShowImage = false; } _folders = await FolderService.GetFoldersAsync(ModuleState.SiteId); if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder) { Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder); if (folder != null) { FolderId = folder.FolderId; } else { FolderId = -1; _message = "Folder Path " + Folder + "Does Not Exist"; _messagetype = MessageType.Error; } } if (FileId != -1) { File file = await FileService.GetFileAsync(FileId); if (file != null) { FolderId = file.FolderId; await OnSelect.InvokeAsync(FileId); } else { FileId = -1; // file does not exist _message = "FileId " + FileId.ToString() + "Does Not Exist"; _messagetype = MessageType.Error; } } await SetImage(); if (!string.IsNullOrEmpty(Filter)) { _filter = "." + Filter.Replace(",", ",."); } await GetFiles(); // create unique id for component _guid = Guid.NewGuid().ToString("N"); _fileinputid = "FileInput_" + _guid; _progressinfoid = "ProgressInfo_" + _guid; _progressbarid = "ProgressBar_" + _guid; } private async Task GetFiles() { _haseditpermission = false; if (Folder == Constants.PackagesFolder) { _haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host); _files = new List(); } else { Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId); if (folder != null) { _haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions); _files = await FileService.GetFilesAsync(FolderId); } else { _haseditpermission = false; _files = new List(); } } if (_filter != "*") { List filtered = new List(); foreach (File file in _files) { if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1) { filtered.Add(file); } } _files = filtered; } } private async Task FolderChanged(ChangeEventArgs e) { _message = string.Empty; try { FolderId = int.Parse((string)e.Value); await GetFiles(); FileId = -1; _file = null; _image = string.Empty; StateHasChanged(); } catch (Exception ex) { await logger.LogError(ex, "Error Loading Files {Error}", ex.Message); _message = Localizer["Error.File.Load"]; _messagetype = MessageType.Error; } } private async Task FileChanged(ChangeEventArgs e) { _message = string.Empty; FileId = int.Parse((string)e.Value); if (FileId != -1) { await OnSelect.InvokeAsync(FileId); } await SetImage(); StateHasChanged(); } private async Task SetImage() { _image = string.Empty; _file = null; if (FileId != -1) { _file = await FileService.GetFileAsync(FileId); if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0) { var maxwidth = 200; var maxheight = 200; var ratioX = (double)maxwidth / (double)_file.ImageWidth; var ratioY = (double)maxheight / (double)_file.ImageHeight; var ratio = ratioX < ratioY ? ratioX : ratioY; _image = "\"""; } } } private async Task UploadFiles() { _message = string.Empty; var interop = new Interop(JSRuntime); var uploads = await interop.GetFiles(_fileinputid); if (uploads.Length > 0) { string restricted = ""; foreach (var upload in uploads) { var extension = (upload.LastIndexOf(".") != -1) ? upload.Substring(upload.LastIndexOf(".") + 1) : ""; if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower())) { restricted += (restricted == "" ? "" : ",") + extension; } } if (restricted == "") { try { // upload the files var posturl = Utilities.TenantUrl(PageState.Alias, "/api/file/upload"); var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString(); await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken); // uploading is asynchronous so we need to wait for the uploads to complete // note that this will only wait a maximum of 15 seconds which may not be long enough for very large file uploads bool success = false; int attempts = 0; while (attempts < 5 && !success) { attempts += 1; Thread.Sleep(1000 * attempts); // progressive retry success = true; List files = await FileService.GetFilesAsync(folder); if (files.Count > 0) { foreach (string upload in uploads) { if (!files.Exists(item => item.Name == upload)) { success = false; } } } } // reset progress indicators await interop.SetElementAttribute(_guid + "ProgressInfo", "style", "display: none;"); await interop.SetElementAttribute(_guid + "ProgressBar", "style", "display: none;"); if (success) { await logger.LogInformation("File Upload Succeeded {Files}", uploads); if (ShowSuccess) { _message = Localizer["Success.File.Upload"]; _messagetype = MessageType.Success; } } else { await logger.LogInformation("File Upload Failed Or Is Still In Progress {Files}", uploads); _message = Localizer["Error.File.Upload"]; _messagetype = MessageType.Error; } // set FileId to first file in upload collection await GetFiles(); var file = _files.Where(item => item.Name == uploads[0]).FirstOrDefault(); if (file != null) { FileId = file.FileId; await SetImage(); await OnUpload.InvokeAsync(FileId); } StateHasChanged(); } catch (Exception ex) { await logger.LogError(ex, "File Upload Failed {Error}", ex.Message); _message = Localizer["Error.File.Upload"]; _messagetype = MessageType.Error; } } else { _message = string.Format(Localizer["Message.File.Restricted"], restricted); _messagetype = MessageType.Warning; } } else { _message = Localizer["Message.File.NotSelected"]; _messagetype = MessageType.Warning; } } private async Task DeleteFile() { _message = string.Empty; try { await FileService.DeleteFileAsync(FileId); await logger.LogInformation("File Deleted {File}", FileId); await OnDelete.InvokeAsync(FileId); _message = Localizer["Success.File.Delete"]; _messagetype = MessageType.Success; await GetFiles(); FileId = -1; await SetImage(); StateHasChanged(); } catch (Exception ex) { await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message); _message = Localizer["Error.File.Delete"]; _messagetype = MessageType.Error; } } public int GetFileId() => FileId; public int GetFolderId() => FolderId; public File GetFile() => _file; public async Task Refresh() { await Refresh(-1); } public async Task Refresh(int fileId) { await GetFiles(); if (fileId != -1) { var file = _files.Where(item => item.FileId == fileId).FirstOrDefault(); if (file != null) { FileId = file.FileId; await SetImage(); } } StateHasChanged(); } }