From c07e766e5766f9bcd83bdbed659457a6be7b2181 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 26 May 2021 12:01:35 -0400 Subject: [PATCH] add support for public content folders --- .gitignore | 2 +- Oqtane.Client/Modules/Admin/Files/Edit.razor | 23 ++- Oqtane.Client/Modules/Admin/Files/Index.razor | 2 +- .../Modules/Admin/UserProfile/Index.razor | 141 ++++++++++-------- Oqtane.Client/Modules/Admin/Users/Edit.razor | 23 +-- .../Modules/Controls/FileManager.razor | 18 ++- .../Modules/Controls/RichTextEditor.razor | 6 +- .../Modules/Controls/RichTextEditorInterop.cs | 6 +- Oqtane.Client/Modules/HtmlText/Edit.razor | 4 +- Oqtane.Client/Modules/HtmlText/Index.razor | 2 +- .../Themes/Controls/Theme/Logo.razor | 20 ++- Oqtane.Server/Controllers/UserController.cs | 1 + .../Infrastructure/DatabaseManager.cs | 1 + .../EntityBuilders/BaseEntityBuilder.cs | 6 +- .../Tenant/02010003_AddFolderType.cs | 34 +++++ Oqtane.Server/Repository/FileRepository.cs | 29 +++- Oqtane.Server/Repository/FolderRepository.cs | 17 ++- Oqtane.Server/Repository/SiteRepository.cs | 20 +-- Oqtane.Server/wwwroot/js/quill-interop.js | 4 +- Oqtane.Shared/Models/File.cs | 12 +- Oqtane.Shared/Models/Folder.cs | 5 + Oqtane.Shared/Shared/FolderTypes.cs | 6 + Oqtane.Shared/Shared/Utilities.cs | 22 +++ 23 files changed, 281 insertions(+), 123 deletions(-) create mode 100644 Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs create mode 100644 Oqtane.Shared/Shared/FolderTypes.cs diff --git a/.gitignore b/.gitignore index 18de70f2..24d48481 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,6 @@ Oqtane.Server/Data/*.db /Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml Oqtane.Server/Content -Oqtane.Server/wwwroot/Packages/**/assets.json +Oqtane.Server/wwwroot/Content Oqtane.Server/wwwroot/Packages/*.log diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index b2ac3b64..4f6054db 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -33,6 +33,24 @@ + + + + + + @if (PageState.QueryString.ContainsKey("id")) + { + + } + else + { + + } + + @@ -60,8 +78,9 @@ @code { private List _folders; private int _folderId = -1; - private string _name; private int _parentId = -1; + private string _name; + private string _type = FolderTypes.Private; private bool _isSystem; private string _permissions = string.Empty; private string _createdBy; @@ -91,6 +110,7 @@ { _parentId = folder.ParentId ?? -1; _name = folder.Name; + _type = folder.Type; _isSystem = folder.IsSystem; _permissions = folder.Permissions; _createdBy = folder.CreatedBy; @@ -150,6 +170,7 @@ } folder.Name = _name; + folder.Type = _type; folder.IsSystem = _isSystem; folder.Permissions = _permissionGrid.GetPermissions(); diff --git a/Oqtane.Client/Modules/Admin/Files/Index.razor b/Oqtane.Client/Modules/Admin/Files/Index.razor index 58990804..bd670d21 100644 --- a/Oqtane.Client/Modules/Admin/Files/Index.razor +++ b/Oqtane.Client/Modules/Admin/Files/Index.razor @@ -39,7 +39,7 @@ - @context.Name + @context.Name @context.ModifiedOn @context.Extension.ToUpper() @Localizer["File"] @string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 4b2874b6..9c15f010 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -5,11 +5,12 @@ @inject IProfileService ProfileService @inject ISettingService SettingService @inject INotificationService NotificationService +@inject IFileService FileService @inject IStringLocalizer Localizer -@if (PageState.User != null && photofileid != -1) +@if (PageState.User != null && photo != null) { - @displayname + @displayname } else { @@ -76,58 +77,58 @@ else @if (profiles != null && settings != null) { - - @foreach (Profile profile in profiles) - { - var p = profile; - if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) +
+ @foreach (Profile profile in profiles) { - if (p.Category != category) + var p = profile; + if (!p.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { + if (p.Category != category) + { + + + + category = p.Category; + } - - - category = p.Category; - } - - - + - + + + } } - } -
+ @p.Category +
- @p.Category -
- - - @if (!string.IsNullOrEmpty(p.Options)) - { - - } - else - { - @if (p.IsRequired) + + + + @if (!string.IsNullOrEmpty(p.Options)) { - + } else { - + @if (p.IsRequired) + { + + } + else + { + + } } - } -
+ } @@ -157,13 +158,14 @@ else - @{ - string input = "___"; - if (context.Body.Contains(input)){ - context.Body = context.Body.Split(input)[0]; - context.Body = context.Body.Replace("\n", ""); - context.Body = context.Body.Replace("\r", ""); - } } + @{ + string input = "___"; + if (context.Body.Contains(input)) + { + context.Body = context.Body.Split(input)[0]; + context.Body = context.Body.Replace("\n", ""); + context.Body = context.Body.Replace("\r", ""); + } } @(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body) @@ -189,13 +191,14 @@ else - @{ - string input = "___"; - if (context.Body.Contains(input)){ - context.Body = context.Body.Split(input)[0]; - context.Body = context.Body.Replace("\n", ""); - context.Body = context.Body.Replace("\r", ""); - } } + @{ + string input = "___"; + if (context.Body.Contains(input)) + { + context.Body = context.Body.Split(input)[0]; + context.Body = context.Body.Replace("\n", ""); + context.Body = context.Body.Replace("\r", ""); + } } @(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body) @@ -218,6 +221,7 @@ else private string displayname = string.Empty; private FileManager filemanager; private int photofileid = -1; + private File photo = null; private List profiles; private Dictionary settings; private string category = string.Empty; @@ -226,7 +230,7 @@ else public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; - protected override async Task OnInitializedAsync() + protected override async Task OnParametersSetAsync() { try { @@ -239,6 +243,12 @@ else if (PageState.User.PhotoFileId != null) { photofileid = PageState.User.PhotoFileId.Value; + photo = await FileService.GetFileAsync(photofileid); + } + else + { + photofileid = -1; + photo = null; } profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId); @@ -280,18 +290,17 @@ else user.Password = password; user.Email = email; user.DisplayName = (displayname == string.Empty ? username : displayname); - user.PhotoFileId = null; - photofileid = filemanager.GetFileId(); - - if (photofileid != -1) + user.PhotoFileId = filemanager.GetFileId(); + if (user.PhotoFileId == -1) { - user.PhotoFileId = photofileid; + user.PhotoFileId = null; } await UserService.UpdateUserAsync(user); await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); await logger.LogInformation("User Profile Saved"); - AddModuleMessage(Localizer["User Profile Updated Successfully"], MessageType.Success); + + NavigationManager.NavigateTo(NavigateUrl()); } else { diff --git a/Oqtane.Client/Modules/Admin/Users/Edit.razor b/Oqtane.Client/Modules/Admin/Users/Edit.razor index be68ff7d..19254613 100644 --- a/Oqtane.Client/Modules/Admin/Users/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Users/Edit.razor @@ -4,11 +4,12 @@ @inject IUserService UserService @inject IProfileService ProfileService @inject ISettingService SettingService +@inject IFileService FileService @inject IStringLocalizer Localizer -@if (PageState.User != null && photofileid != -1) +@if (PageState.User != null && photo != null) { - @displayname + @displayname } else { @@ -133,6 +134,7 @@ else private string displayname = string.Empty; private FileManager filemanager; private int photofileid = -1; + private File photo = null; private List profiles; private Dictionary settings; private string category = string.Empty; @@ -146,7 +148,7 @@ else public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; - protected override async Task OnInitializedAsync() + protected override async Task OnParametersSetAsync() { try { @@ -159,12 +161,16 @@ else username = user.Username; email = user.Email; displayname = user.DisplayName; - if (user.PhotoFileId != null) { photofileid = user.PhotoFileId.Value; + photo = await FileService.GetFileAsync(photofileid); + } + else + { + photofileid = -1; + photo = null; } - settings = await SettingService.GetUserSettingsAsync(user.UserId); createdby = user.CreatedBy; createdon = user.CreatedOn; @@ -200,11 +206,10 @@ else user.Email = email; user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname; user.PhotoFileId = null; - photofileid = filemanager.GetFileId(); - - if (photofileid != -1) + user.PhotoFileId = filemanager.GetFileId(); + if (user.PhotoFileId == -1) { - user.PhotoFileId = photofileid; + user.PhotoFileId = null; } user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted)); diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 90bc48c5..df468bbe 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -79,6 +79,7 @@ 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; @@ -199,6 +200,7 @@ FolderId = int.Parse((string)e.Value); await GetFiles(); FileId = -1; + _file = null; _image = string.Empty; StateHasChanged(); } @@ -223,21 +225,22 @@ private async Task SetImage() { _image = string.Empty; + _file = null; if (FileId != -1) { - File file = await FileService.GetFileAsync(FileId); - if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0) + _file = await FileService.GetFileAsync(FileId); + if (_file != null && _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 ratioX = (double)maxwidth / (double)_file.ImageWidth; + var ratioY = (double)maxheight / (double)_file.ImageHeight; var ratio = ratioX < ratioY ? ratioX : ratioY; - _image = "\"""; + _image = "\"""; } } } @@ -331,4 +334,5 @@ public int GetFileId() => FileId; + public File GetFile() => _file; } diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 1d3a2751..ce50272d 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -191,11 +191,11 @@ _message = string.Empty; if (_filemanagervisible) { - var fileid = _fileManager.GetFileId(); - if (fileid != -1) + var file = _fileManager.GetFile(); + if (file != null) { var interop = new RichTextEditorInterop(JSRuntime); - await interop.InsertImage(_editorElement, ContentUrl(fileid)); + await interop.InsertImage(_editorElement, file.Url, file.Name); _filemanagervisible = false; } else diff --git a/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs b/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs index 0ecce251..6765cad9 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs +++ b/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using System.Threading.Tasks; @@ -105,13 +105,13 @@ namespace Oqtane.Modules.Controls } } - public Task InsertImage(ElementReference quillElement, string imageUrl) + public Task InsertImage(ElementReference quillElement, string imageUrl, string altText) { try { _jsRuntime.InvokeAsync( "Oqtane.RichTextEditor.insertQuillImage", - quillElement, imageUrl); + quillElement, imageUrl, altText); return Task.CompletedTask; } catch diff --git a/Oqtane.Client/Modules/HtmlText/Edit.razor b/Oqtane.Client/Modules/HtmlText/Edit.razor index 6517d56f..5e93e330 100644 --- a/Oqtane.Client/Modules/HtmlText/Edit.razor +++ b/Oqtane.Client/Modules/HtmlText/Edit.razor @@ -51,7 +51,7 @@ if (htmltext != null) { _content = htmltext.Content; - _content = _content.Replace(Constants.ContentUrl, Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl)); + _content = Utilities.FormatContent(_content, PageState.Alias, "render"); _createdby = htmltext.CreatedBy; _createdon = htmltext.CreatedOn; _modifiedby = htmltext.ModifiedBy; @@ -72,7 +72,7 @@ private async Task SaveContent() { string content = await RichTextEditorHtml.GetHtml(); - content = content.Replace(Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl), Constants.ContentUrl); + content = Utilities.FormatContent(content, PageState.Alias, "save"); try { diff --git a/Oqtane.Client/Modules/HtmlText/Index.razor b/Oqtane.Client/Modules/HtmlText/Index.razor index 17deeade..21263f72 100644 --- a/Oqtane.Client/Modules/HtmlText/Index.razor +++ b/Oqtane.Client/Modules/HtmlText/Index.razor @@ -26,7 +26,7 @@ if (htmltext != null) { content = htmltext.Content; - content = content.Replace(Constants.ContentUrl, Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl)); + content = Utilities.FormatContent(content, PageState.Alias, "render"); } } catch (Exception ex) diff --git a/Oqtane.Client/Themes/Controls/Theme/Logo.razor b/Oqtane.Client/Themes/Controls/Theme/Logo.razor index 1fa496fb..89483bd0 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Logo.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Logo.razor @@ -1,12 +1,24 @@ -@namespace Oqtane.Themes.Controls -@inherits ThemeControlBase +@namespace Oqtane.Themes.Controls +@inherits ThemeControlBase +@inject IFileService FileService -@if (PageState.Site.LogoFileId != null) +@if (file != null) { } +@code { + private File file = null; + + protected override async Task OnParametersSetAsync() + { + if (PageState.Site.LogoFileId != null && file?.FileId != PageState.Site.LogoFileId.Value) + { + file = await FileService.GetFileAsync(PageState.Site.LogoFileId.Value); + } + } +} \ No newline at end of file diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 19a79949..1d1434bf 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -173,6 +173,7 @@ namespace Oqtane.Controllers SiteId = folder.SiteId, ParentId = folder.FolderId, Name = "My Folder", + Type = FolderTypes.Private, Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true, diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 47c19692..7b19f7c8 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -593,6 +593,7 @@ namespace Oqtane.Infrastructure SiteId = folder.SiteId, ParentId = folder.FolderId, Name = "My Folder", + Type = FolderTypes.Private, Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true, diff --git a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs index f25010d5..fb2fd69a 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/BaseEntityBuilder.cs @@ -231,7 +231,6 @@ namespace Oqtane.Migrations.EntityBuilders public void DeleteFromTable(string condition = "") { var deleteSql = $"DELETE FROM {RewriteName(EntityTableName)} "; - if(!string.IsNullOrEmpty(condition)) { deleteSql += $"WHERE {condition}"; @@ -241,11 +240,8 @@ namespace Oqtane.Migrations.EntityBuilders public void UpdateColumn(string columnName, string value, string condition = "") { - var updateValue = value; - var updateSql = $"UPDATE {RewriteName(EntityTableName)} SET {RewriteName(columnName)} = {value} "; - - if(!string.IsNullOrEmpty(condition)) + if (!string.IsNullOrEmpty(condition)) { updateSql += $"WHERE {condition}"; } diff --git a/Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs b/Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs new file mode 100644 index 00000000..f6d3905b --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; +using Oqtane.Shared; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.02.01.00.03")] + public class AddFolderType : MultiDatabaseMigration + { + public AddFolderType(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); + + //Add Type column and initialize + folderEntityBuilder.AddStringColumn("Type", 50, true, true); + folderEntityBuilder.UpdateColumn("Type", "'" + FolderTypes.Private + "'"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var folderEntityBuilder = new FolderEntityBuilder(migrationBuilder, ActiveDatabase); + + folderEntityBuilder.DropColumn("Type"); + } + } +} diff --git a/Oqtane.Server/Repository/FileRepository.cs b/Oqtane.Server/Repository/FileRepository.cs index 07866810..f86a059d 100644 --- a/Oqtane.Server/Repository/FileRepository.cs +++ b/Oqtane.Server/Repository/FileRepository.cs @@ -1,8 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; +using Oqtane.Infrastructure; using Oqtane.Models; using Oqtane.Shared; using File = Oqtane.Models.File; @@ -14,21 +15,25 @@ namespace Oqtane.Repository private TenantDBContext _db; private readonly IPermissionRepository _permissions; private readonly IFolderRepository _folderRepository; + private readonly ITenantManager _tenants; - public FileRepository(TenantDBContext context, IPermissionRepository permissions, IFolderRepository folderRepository) + public FileRepository(TenantDBContext context, IPermissionRepository permissions, IFolderRepository folderRepository, ITenantManager tenants) { _db = context; _permissions = permissions; _folderRepository = folderRepository; + _tenants = tenants; } public IEnumerable GetFiles(int folderId) { IEnumerable permissions = _permissions.GetPermissions(EntityNames.Folder, folderId).ToList(); IEnumerable files = _db.File.Where(item => item.FolderId == folderId).Include(item => item.Folder); + var alias = _tenants.GetAlias(); foreach (File file in files) { file.Folder.Permissions = permissions.EncodePermissions(); + file.Url = GetFileUrl(file, alias); } return files; } @@ -49,7 +54,9 @@ namespace Oqtane.Repository public File GetFile(int fileId) { - return GetFile(fileId, true); + File file = GetFile(fileId, true); + file.Url = GetFileUrl(file, _tenants.GetAlias()); + return file; } public File GetFile(int fileId, bool tracking) @@ -68,6 +75,7 @@ namespace Oqtane.Repository { IEnumerable permissions = _permissions.GetPermissions(EntityNames.Folder, file.FolderId).ToList(); file.Folder.Permissions = permissions.EncodePermissions(); + file.Url = GetFileUrl(file, _tenants.GetAlias()); } return file; } @@ -92,5 +100,20 @@ namespace Oqtane.Repository var filepath = Path.Combine(_folderRepository.GetFolderPath(folder), file.Name); return filepath; } + + private string GetFileUrl(File file, Alias alias) + { + string url = ""; + switch (file.Folder.Type) + { + case FolderTypes.Private: + url = Utilities.ContentUrl(alias, file.FileId); + break; + case FolderTypes.Public: + url = "/" + Utilities.UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", file.Folder.SiteId.ToString(), file.Folder.Path) + file.Name; + break; + } + return url; + } } } diff --git a/Oqtane.Server/Repository/FolderRepository.cs b/Oqtane.Server/Repository/FolderRepository.cs index dc7125bb..13797658 100644 --- a/Oqtane.Server/Repository/FolderRepository.cs +++ b/Oqtane.Server/Repository/FolderRepository.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; +using Oqtane.Infrastructure; using Oqtane.Models; using Oqtane.Shared; @@ -13,9 +14,9 @@ namespace Oqtane.Repository private TenantDBContext _db; private readonly IPermissionRepository _permissions; private readonly IWebHostEnvironment _environment; - private readonly ITenantResolver _tenants; + private readonly ITenantManager _tenants; - public FolderRepository(TenantDBContext context, IPermissionRepository permissions,IWebHostEnvironment environment, ITenantResolver tenants) + public FolderRepository(TenantDBContext context, IPermissionRepository permissions,IWebHostEnvironment environment, ITenantManager tenants) { _db = context; _permissions = permissions; @@ -99,7 +100,17 @@ namespace Oqtane.Repository public string GetFolderPath(Folder folder) { - return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); + string path = ""; + switch (folder.Type) + { + case FolderTypes.Private: + path = Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); + break; + case FolderTypes.Public: + path = Utilities.PathCombine(_environment.WebRootPath, "Content", "Tenants", _tenants.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); + break; + } + return path; } } diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 20a03940..ae2a74a8 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -648,25 +648,25 @@ namespace Oqtane.Repository _roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true}); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "FirstName", Title = "First Name", Description = "Your First Or Given Name", Category = "Name", ViewOrder = 1, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "FirstName", Title = "First Name", Description = "Your First Or Given Name", Category = "Name", ViewOrder = 1, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = ""}); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "LastName", Title = "Last Name", Description = "Your Last Or Family Name", Category = "Name", ViewOrder = 2, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "LastName", Title = "Last Name", Description = "Your Last Or Family Name", Category = "Name", ViewOrder = 2, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "Street", Title = "Street", Description = "Street Or Building Address", Category = "Address", ViewOrder = 3, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "Street", Title = "Street", Description = "Street Or Building Address", Category = "Address", ViewOrder = 3, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile( - new Profile {SiteId = site.SiteId, Name = "City", Title = "City", Description = "City", Category = "Address", ViewOrder = 4, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + new Profile {SiteId = site.SiteId, Name = "City", Title = "City", Description = "City", Category = "Address", ViewOrder = 4, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "Region", Title = "Region", Description = "State Or Province", Category = "Address", ViewOrder = 5, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "Region", Title = "Region", Description = "State Or Province", Category = "Address", ViewOrder = 5, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "Country", Title = "Country", Description = "Country", Category = "Address", ViewOrder = 6, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "Country", Title = "Country", Description = "Country", Category = "Address", ViewOrder = 6, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "PostalCode", Title = "Postal Code", Description = "Postal Code Or Zip Code", Category = "Address", ViewOrder = 7, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "PostalCode", Title = "Postal Code", Description = "Postal Code Or Zip Code", Category = "Address", ViewOrder = 7, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); _profileRepository.AddProfile(new Profile - {SiteId = site.SiteId, Name = "Phone", Title = "Phone Number", Description = "Phone Number", Category = "Contact", ViewOrder = 8, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false}); + {SiteId = site.SiteId, Name = "Phone", Title = "Phone Number", Description = "Phone Number", Category = "Contact", ViewOrder = 8, MaxLength = 50, DefaultValue = "", IsRequired = false, IsPrivate = false, Options = "" }); Folder folder = _folderRepository.AddFolder(new Folder { - SiteId = site.SiteId, ParentId = null, Name = "Root", Path = "", Order = 1, IsSystem = true, + SiteId = site.SiteId, ParentId = null, Name = "Root", Type = FolderTypes.Private, Path = "", Order = 1, IsSystem = true, Permissions = new List { new Permission(PermissionNames.Browse, RoleNames.Admin, true), @@ -676,7 +676,7 @@ namespace Oqtane.Repository }); _folderRepository.AddFolder(new Folder { - SiteId = site.SiteId, ParentId = folder.FolderId, Name = "Users", Path = Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true, + SiteId = site.SiteId, ParentId = folder.FolderId, Name = "Users", Type = FolderTypes.Private, Path = Utilities.PathCombine("Users",Path.DirectorySeparatorChar.ToString()), Order = 1, IsSystem = true, Permissions = new List { new Permission(PermissionNames.Browse, RoleNames.Admin, true), diff --git a/Oqtane.Server/wwwroot/js/quill-interop.js b/Oqtane.Server/wwwroot/js/quill-interop.js index 13664fd4..e5610a9e 100644 --- a/Oqtane.Server/wwwroot/js/quill-interop.js +++ b/Oqtane.Server/wwwroot/js/quill-interop.js @@ -35,7 +35,7 @@ Oqtane.RichTextEditor = { enableQuillEditor: function (editorElement, mode) { editorElement.__quill.enable(mode); }, - insertQuillImage: function (quillElement, imageURL) { + insertQuillImage: function (quillElement, imageURL, altText) { var Delta = Quill.import('delta'); editorIndex = 0; @@ -47,6 +47,6 @@ Oqtane.RichTextEditor = { new Delta() .retain(editorIndex) .insert({ image: imageURL }, - { alt: imageURL })); + { alt: altText })); } }; diff --git a/Oqtane.Shared/Models/File.cs b/Oqtane.Shared/Models/File.cs index f09f05d9..efba620a 100644 --- a/Oqtane.Shared/Models/File.cs +++ b/Oqtane.Shared/Models/File.cs @@ -1,4 +1,6 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; +using Oqtane.Shared; namespace Oqtane.Models { @@ -41,7 +43,7 @@ namespace Oqtane.Models /// This is calculated at time of Upload, so if the file is manually replaced, the value will be wrong. /// public int ImageHeight { get; set; } - + /// /// The width of an image (if the file is an image) in pixels. /// This is calculated at time of Upload, so if the file is manually replaced, the value will be wrong. @@ -65,7 +67,7 @@ namespace Oqtane.Models #endregion #region Extended IAuditable Properties, may be moved to an Interface some day so not documented yet - + public string DeletedBy { get; set; } public DateTime? DeletedOn { get; set; } public bool IsDeleted { get; set; } @@ -78,5 +80,11 @@ namespace Oqtane.Models /// TODO: not sure if this is always populated, must verify and document /// public Folder Folder { get; set; } + + /// + /// url for accessing file + /// + [NotMapped] + public string Url { get; set; } } } diff --git a/Oqtane.Shared/Models/Folder.cs b/Oqtane.Shared/Models/Folder.cs index f995843c..ebe80584 100644 --- a/Oqtane.Shared/Models/Folder.cs +++ b/Oqtane.Shared/Models/Folder.cs @@ -23,6 +23,11 @@ namespace Oqtane.Models /// public int? ParentId { get; set; } + /// + /// Folder type - based on FolderTypes + /// + public string Type { get; set; } + /// /// Folder name /// diff --git a/Oqtane.Shared/Shared/FolderTypes.cs b/Oqtane.Shared/Shared/FolderTypes.cs new file mode 100644 index 00000000..ee314ada --- /dev/null +++ b/Oqtane.Shared/Shared/FolderTypes.cs @@ -0,0 +1,6 @@ +namespace Oqtane.Shared { + public class FolderTypes { + public const string Private = "Private"; + public const string Public = "Public"; + } +} diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 44b293f7..23397f89 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -113,6 +113,23 @@ namespace Oqtane.Shared url = (!url.StartsWith("/")) ? "/" + url : url; return (alias != null && !string.IsNullOrEmpty(alias.Path)) ? "/" + alias.Path + url : url; } + + public static string FormatContent(string content, Alias alias, string operation) + { + switch (operation) + { + case "save": + content = content.Replace(UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", alias.SiteId.ToString()), "[siteroot]"); + content = content.Replace(alias.Path + Constants.ContentUrl, Constants.ContentUrl); + break; + case "render": + content = content.Replace("[siteroot]", UrlCombine("Content", "Tenants", alias.TenantId.ToString(), "Sites", alias.SiteId.ToString())); + content = content.Replace(Constants.ContentUrl, alias.Path + Constants.ContentUrl); + break; + } + return content; + } + public static string GetTypeName(string fullyqualifiedtypename) { if (fullyqualifiedtypename.Contains(",")) @@ -325,6 +342,11 @@ namespace Oqtane.Shared return Path.Combine(segments).TrimEnd(); } + public static string UrlCombine(params string[] segments) + { + return string.Join("/", segments); + } + public static bool IsPathValid(this Folder folder) { return IsPathOrFileValid(folder.Name);