diff --git a/Oqtane.Client/Modules/Admin/Files/Add.razor b/Oqtane.Client/Modules/Admin/Files/Add.razor new file mode 100644 index 00000000..04fc81ea --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Files/Add.razor @@ -0,0 +1,51 @@ +@namespace Oqtane.Modules.Admin.Files +@inherits ModuleBase +@inject NavigationManager NavigationManager +@inject IFileService FileService + + + + + + +
+ + + +
+ +Cancel + + +@code { + public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } + + FileUpload fileupload; + + private async Task UploadFile() + { + string[] files = await fileupload.GetFiles(); + if (files.Length > 0) + { + try + { + if (await FileService.UploadFilesAsync(PageState.Site.SiteRootPath, files, "")) + { + ModuleInstance.AddModuleMessage("Files Uploaded Successfully", MessageType.Success); + } + else + { + ModuleInstance.AddModuleMessage("Upload Failed", MessageType.Error); + } + } + catch (Exception ex) + { + ModuleInstance.AddModuleMessage("Upload Failed. " + ex.Message, MessageType.Error); + } + } + else + { + ModuleInstance.AddModuleMessage("You Must Select Some Files To Upload", MessageType.Warning); + } + } +} diff --git a/Oqtane.Client/Modules/Admin/Files/Index.razor b/Oqtane.Client/Modules/Admin/Files/Index.razor new file mode 100644 index 00000000..5f94d0ac --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Files/Index.razor @@ -0,0 +1,44 @@ +@namespace Oqtane.Modules.Admin.Files +@inherits ModuleBase +@inject NavigationManager NavigationManager +@inject IFileService FileService + +@if (Files == null) +{ +

Loading...

+} +else +{ + + + +
+ Name +   +
+ + @context + + + + +
+} + +@code { + public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Admin; } } + + List Files; + + protected override async Task OnParametersSetAsync() + { + Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); + } + + private async Task DeleteFile(string filename) + { + await FileService.DeleteFileAsync(PageState.Site.SiteRootPath, filename); + Files = await FileService.GetFilesAsync(PageState.Site.SiteRootPath); + ModuleInstance.AddModuleMessage("File Deleted", MessageType.Success); + } +} \ No newline at end of file diff --git a/Oqtane.Client/Modules/Admin/Users/Delete.razor b/Oqtane.Client/Modules/Admin/Users/Delete.razor index 8e68735a..19705668 100644 --- a/Oqtane.Client/Modules/Admin/Users/Delete.razor +++ b/Oqtane.Client/Modules/Admin/Users/Delete.razor @@ -58,7 +58,6 @@ string username = ""; string email = ""; string displayname = ""; - string category = ""; string createdby; DateTime createdon; string modifiedby; diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index 3e3c30b0..45ddf82e 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -88,5 +88,9 @@ classname = "btn btn-warning"; // alert developer of missing module comtrol } } + else + { + authorized = false; + } } } diff --git a/Oqtane.Client/Services/FileService.cs b/Oqtane.Client/Services/FileService.cs index eff93274..296764d1 100644 --- a/Oqtane.Client/Services/FileService.cs +++ b/Oqtane.Client/Services/FileService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; @@ -37,19 +38,34 @@ namespace Oqtane.Services bool success = false; var interop = new Interop(jsRuntime); await interop.UploadFiles(apiurl + "/upload", Folder, FileUploadName); - List files = await GetFilesAsync(Folder); - if (files.Count > 0) + + // uploading files is asynchronous so we need to wait for the upload to complete + int attempts = 0; + while (attempts < 5 && success == false) { - success = true; - foreach (string file in Files) + Thread.Sleep(2000); // wait 2 seconds + + List files = await GetFilesAsync(Folder); + if (files.Count > 0) { - if (!files.Contains(file)) + success = true; + foreach (string file in Files) { - success = false; + if (!files.Contains(file)) + { + success = false; + } } } + attempts += 1; } + return success; } + + public async Task DeleteFileAsync(string Folder, string File) + { + await http.DeleteAsync(apiurl + "?folder=" + Folder + "&file=" + File); + } } } diff --git a/Oqtane.Client/Services/Interfaces/IFileService.cs b/Oqtane.Client/Services/Interfaces/IFileService.cs index 06bb5828..1cff111c 100644 --- a/Oqtane.Client/Services/Interfaces/IFileService.cs +++ b/Oqtane.Client/Services/Interfaces/IFileService.cs @@ -8,5 +8,6 @@ namespace Oqtane.Services { Task> GetFilesAsync(string Folder); Task UploadFilesAsync(string Folder, string[] Files, string FileUploadName); + Task DeleteFileAsync(string Folder, string File); } } diff --git a/Oqtane.Client/Themes/Controls/Logo.razor b/Oqtane.Client/Themes/Controls/Logo.razor index 616569fb..192a0f66 100644 --- a/Oqtane.Client/Themes/Controls/Logo.razor +++ b/Oqtane.Client/Themes/Controls/Logo.razor @@ -6,12 +6,11 @@ @code { string logo = ""; - protected override Task OnParametersSetAsync() + protected override void OnParametersSet() { if (PageState.Site.Logo != "") { - logo = "\"""; + logo = "\"""; } - return Task.CompletedTask; } } \ No newline at end of file diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 43057e6f..36e27102 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -1,6 +1,8 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Oqtane.Shared; using System; using System.Collections.Generic; using System.IO; @@ -12,7 +14,8 @@ namespace Oqtane.Controllers public class FileController : Controller { private readonly IWebHostEnvironment environment; - + private readonly string WhiteList = "jpg,jpeg,jpe,gif,bmp,png,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg"; + public FileController(IWebHostEnvironment environment) { this.environment = environment; @@ -23,14 +26,12 @@ namespace Oqtane.Controllers public IEnumerable Get(string folder) { List files = new List(); - folder = folder.Replace("/", "\\"); - if (folder.StartsWith("\\")) folder = folder.Substring(1); - folder = Path.Combine(environment.WebRootPath, folder); + folder = GetFolder(folder); if (Directory.Exists(folder)) { - foreach(string file in Directory.GetFiles(folder)) + foreach (string file in Directory.GetFiles(folder)) { - files.Add(file); + files.Add(Path.GetFileName(file)); } } return files; @@ -38,16 +39,12 @@ namespace Oqtane.Controllers // POST api//upload [HttpPost("upload")] + [Authorize(Roles = Constants.AdminRole)] public async Task UploadFile(string folder, IFormFile file) { if (file.Length > 0) { - if (!folder.Contains(":\\")) - { - folder = folder.Replace("/", "\\"); - if (folder.StartsWith("\\")) folder = folder.Substring(1); - folder = Path.Combine(environment.WebRootPath, folder); - } + folder = GetFolder(folder); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); @@ -85,7 +82,7 @@ namespace Oqtane.Controllers await chunk.CopyToAsync(stream); } } - catch + catch { success = false; } @@ -99,6 +96,13 @@ namespace Oqtane.Controllers { System.IO.File.Delete(filepart); } + + // check for allowable file extensions + if (!WhiteList.Contains(Path.GetExtension(filename).Replace(".", ""))) + { + System.IO.File.Delete(Path.Combine(folder, filename)); + success = false; + } } } @@ -113,5 +117,24 @@ namespace Oqtane.Controllers } } } + + // DELETE api//?folder=x&file=y + [HttpDelete] + [Authorize(Roles = Constants.AdminRole)] + public void Delete(string folder, string file) + { + file = Path.Combine(GetFolder(folder) + file); + if (System.IO.File.Exists(file)) + { + System.IO.File.Delete(file); + } + } + + private string GetFolder(string folder) + { + folder = folder.Replace("/", "\\"); + if (folder.StartsWith("\\")) folder = folder.Substring(1); + return Path.Combine(environment.WebRootPath, folder); + } } -} +} \ No newline at end of file diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 235b5541..d649b666 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -59,11 +59,8 @@ namespace Oqtane.Repository SiteTemplate.Add(new PageTemplate { Name = "Page Management", Parent = "Admin", Path = "admin/pages", Order = 1, Icon = "layers", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Pages, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Page Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } }}); - SiteTemplate.Add(new PageTemplate { Name = "Module Management", Parent = "Admin", Path = "admin/modules", Order = 1, Icon = "browser", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.ModuleDefinitions, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Module Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } - }}); - SiteTemplate.Add(new PageTemplate { Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Order = 1, Icon = "brush", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Themes, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Theme Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + SiteTemplate.Add(new PageTemplate { Name = "File Management", Parent = "Admin", Path = "admin/files", Order = 1, Icon = "file", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Files, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "File Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "User Management", Parent = "Admin", Path = "admin/users", Order = 1, Icon = "person", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Users, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } @@ -74,6 +71,12 @@ namespace Oqtane.Repository SiteTemplate.Add(new PageTemplate { Name = "Tenant Management", Parent = "Admin", Path = "admin/tenants", Order = 1, Icon = "list", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Tenants, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Tenant Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } }}); + SiteTemplate.Add(new PageTemplate { Name = "Module Management", Parent = "Admin", Path = "admin/modules", Order = 1, Icon = "browser", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.ModuleDefinitions, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Module Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + }}); + SiteTemplate.Add(new PageTemplate { Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Order = 1, Icon = "brush", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Themes, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Theme Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + }}); SiteTemplate.Add(new PageTemplate { Name = "Upgrade Service", Parent = "Admin", Path = "admin/upgrade", Order = 1, Icon = "aperture", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Upgrade, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Upgrade Service", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } }}); diff --git a/Oqtane.Shared/Models/Alias.cs b/Oqtane.Shared/Models/Alias.cs index 92442601..072b7e12 100644 --- a/Oqtane.Shared/Models/Alias.cs +++ b/Oqtane.Shared/Models/Alias.cs @@ -57,41 +57,5 @@ namespace Oqtane.Models } } } - - [NotMapped] - public string TenantRootPath - { - get - { - return "Tenants/" + TenantId.ToString() + "/"; - } - } - - [NotMapped] - public string TenantRootUrl - { - get - { - return BaseUrl + "/Tenants/" + TenantId.ToString() + "/"; - } - } - - [NotMapped] - public string SiteRootPath - { - get - { - return "Tenants/" + TenantId.ToString() + "/Sites/" + SiteId.ToString() + "/"; - } - } - - [NotMapped] - public string SiteRootUrl - { - get - { - return BaseUrl + "/Tenants/" + TenantId.ToString() + "/Sites/" + SiteId.ToString() + "/"; - } - } } } diff --git a/Oqtane.Shared/Models/Site.cs b/Oqtane.Shared/Models/Site.cs index cf8d5751..81f05244 100644 --- a/Oqtane.Shared/Models/Site.cs +++ b/Oqtane.Shared/Models/Site.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; namespace Oqtane.Models { @@ -19,5 +20,23 @@ namespace Oqtane.Models public string DeletedBy { get; set; } public DateTime? DeletedOn { get; set; } public bool IsDeleted { get; set; } + + [NotMapped] + public string TenantRootPath + { + get + { + return "Tenants/" + TenantId.ToString() + "/"; + } + } + + [NotMapped] + public string SiteRootPath + { + get + { + return "Tenants/" + TenantId.ToString() + "/Sites/" + SiteId.ToString() + "/"; + } + } } }