add support for public content folders
This commit is contained in:
parent
1d171d2e56
commit
c07e766e57
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -18,6 +18,6 @@ Oqtane.Server/Data/*.db
|
||||||
|
|
||||||
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml
|
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml
|
||||||
Oqtane.Server/Content
|
Oqtane.Server/Content
|
||||||
Oqtane.Server/wwwroot/Packages/**/assets.json
|
Oqtane.Server/wwwroot/Content
|
||||||
Oqtane.Server/wwwroot/Packages/*.log
|
Oqtane.Server/wwwroot/Packages/*.log
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,24 @@
|
||||||
<input id="name" class="form-control" @bind="@_name" />
|
<input id="name" class="form-control" @bind="@_name" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label for="type" HelpText="Select the folder type. Private folders are only accessible by authorized users. Public folders can be accessed by all users" ResourceKey="Name">Type: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if (PageState.QueryString.ContainsKey("id"))
|
||||||
|
{
|
||||||
|
<input id="type" class="form-control" readonly @bind="@_type" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<select id="type" class="form-control" @bind="@_type">
|
||||||
|
<option value="@FolderTypes.Private">@Localizer[FolderTypes.Private]</option>
|
||||||
|
<option value="@FolderTypes.Public">@Localizer[FolderTypes.Public]</option>
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" align="center">
|
<td colspan="2" align="center">
|
||||||
<Label For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
<Label For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
||||||
|
@ -60,8 +78,9 @@
|
||||||
@code {
|
@code {
|
||||||
private List<Folder> _folders;
|
private List<Folder> _folders;
|
||||||
private int _folderId = -1;
|
private int _folderId = -1;
|
||||||
private string _name;
|
|
||||||
private int _parentId = -1;
|
private int _parentId = -1;
|
||||||
|
private string _name;
|
||||||
|
private string _type = FolderTypes.Private;
|
||||||
private bool _isSystem;
|
private bool _isSystem;
|
||||||
private string _permissions = string.Empty;
|
private string _permissions = string.Empty;
|
||||||
private string _createdBy;
|
private string _createdBy;
|
||||||
|
@ -91,6 +110,7 @@
|
||||||
{
|
{
|
||||||
_parentId = folder.ParentId ?? -1;
|
_parentId = folder.ParentId ?? -1;
|
||||||
_name = folder.Name;
|
_name = folder.Name;
|
||||||
|
_type = folder.Type;
|
||||||
_isSystem = folder.IsSystem;
|
_isSystem = folder.IsSystem;
|
||||||
_permissions = folder.Permissions;
|
_permissions = folder.Permissions;
|
||||||
_createdBy = folder.CreatedBy;
|
_createdBy = folder.CreatedBy;
|
||||||
|
@ -150,6 +170,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
folder.Name = _name;
|
folder.Name = _name;
|
||||||
|
folder.Type = _type;
|
||||||
folder.IsSystem = _isSystem;
|
folder.IsSystem = _isSystem;
|
||||||
folder.Permissions = _permissionGrid.GetPermissions();
|
folder.Permissions = _permissionGrid.GetPermissions();
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
|
<td><ActionLink Action="Details" Text="Edit" Parameters="@($"id=" + context.FileId.ToString())" ResourceKey="Details" /></td>
|
||||||
<td><ActionDialog Header="Delete File" Message="@Localizer["Are You Sure You Wish To Delete {0}?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
|
<td><ActionDialog Header="Delete File" Message="@Localizer["Are You Sure You Wish To Delete {0}?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFile(context))" ResourceKey="DeleteFile" /></td>
|
||||||
<td><a href="@(ContentUrl(context.FileId))" target="_new">@context.Name</a></td>
|
<td><a href="@context.Url" target="_new">@context.Name</a></td>
|
||||||
<td>@context.ModifiedOn</td>
|
<td>@context.ModifiedOn</td>
|
||||||
<td>@context.Extension.ToUpper() @Localizer["File"]</td>
|
<td>@context.Extension.ToUpper() @Localizer["File"]</td>
|
||||||
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
|
<td>@string.Format("{0:0.00}", ((decimal)context.Size / 1000)) KB</td>
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
@inject IProfileService ProfileService
|
@inject IProfileService ProfileService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
|
@inject IFileService FileService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
|
||||||
@if (PageState.User != null && photofileid != -1)
|
@if (PageState.User != null && photo != null)
|
||||||
{
|
{
|
||||||
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
<img src="@photo.Url" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -159,7 +160,8 @@ else
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
@{
|
@{
|
||||||
string input = "___";
|
string input = "___";
|
||||||
if (context.Body.Contains(input)){
|
if (context.Body.Contains(input))
|
||||||
|
{
|
||||||
context.Body = context.Body.Split(input)[0];
|
context.Body = context.Body.Split(input)[0];
|
||||||
context.Body = context.Body.Replace("\n", "");
|
context.Body = context.Body.Replace("\n", "");
|
||||||
context.Body = context.Body.Replace("\r", "");
|
context.Body = context.Body.Replace("\r", "");
|
||||||
|
@ -191,7 +193,8 @@ else
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
@{
|
@{
|
||||||
string input = "___";
|
string input = "___";
|
||||||
if (context.Body.Contains(input)){
|
if (context.Body.Contains(input))
|
||||||
|
{
|
||||||
context.Body = context.Body.Split(input)[0];
|
context.Body = context.Body.Split(input)[0];
|
||||||
context.Body = context.Body.Replace("\n", "");
|
context.Body = context.Body.Replace("\n", "");
|
||||||
context.Body = context.Body.Replace("\r", "");
|
context.Body = context.Body.Replace("\r", "");
|
||||||
|
@ -218,6 +221,7 @@ else
|
||||||
private string displayname = string.Empty;
|
private string displayname = string.Empty;
|
||||||
private FileManager filemanager;
|
private FileManager filemanager;
|
||||||
private int photofileid = -1;
|
private int photofileid = -1;
|
||||||
|
private File photo = null;
|
||||||
private List<Profile> profiles;
|
private List<Profile> profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
|
@ -226,7 +230,7 @@ else
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -239,6 +243,12 @@ else
|
||||||
if (PageState.User.PhotoFileId != null)
|
if (PageState.User.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = PageState.User.PhotoFileId.Value;
|
photofileid = PageState.User.PhotoFileId.Value;
|
||||||
|
photo = await FileService.GetFileAsync(photofileid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
photofileid = -1;
|
||||||
|
photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
|
@ -280,18 +290,17 @@ else
|
||||||
user.Password = password;
|
user.Password = password;
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
photofileid = filemanager.GetFileId();
|
if (user.PhotoFileId == -1)
|
||||||
|
|
||||||
if (photofileid != -1)
|
|
||||||
{
|
{
|
||||||
user.PhotoFileId = photofileid;
|
user.PhotoFileId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await UserService.UpdateUserAsync(user);
|
await UserService.UpdateUserAsync(user);
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||||
await logger.LogInformation("User Profile Saved");
|
await logger.LogInformation("User Profile Saved");
|
||||||
AddModuleMessage(Localizer["User Profile Updated Successfully"], MessageType.Success);
|
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IProfileService ProfileService
|
@inject IProfileService ProfileService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject IFileService FileService
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
|
|
||||||
@if (PageState.User != null && photofileid != -1)
|
@if (PageState.User != null && photo != null)
|
||||||
{
|
{
|
||||||
<img src="@(ContentUrl(photofileid))" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
<img src="@photo.Url" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -133,6 +134,7 @@ else
|
||||||
private string displayname = string.Empty;
|
private string displayname = string.Empty;
|
||||||
private FileManager filemanager;
|
private FileManager filemanager;
|
||||||
private int photofileid = -1;
|
private int photofileid = -1;
|
||||||
|
private File photo = null;
|
||||||
private List<Profile> profiles;
|
private List<Profile> profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
|
@ -146,7 +148,7 @@ else
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -159,12 +161,16 @@ else
|
||||||
username = user.Username;
|
username = user.Username;
|
||||||
email = user.Email;
|
email = user.Email;
|
||||||
displayname = user.DisplayName;
|
displayname = user.DisplayName;
|
||||||
|
|
||||||
if (user.PhotoFileId != null)
|
if (user.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = user.PhotoFileId.Value;
|
photofileid = user.PhotoFileId.Value;
|
||||||
|
photo = await FileService.GetFileAsync(photofileid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
photofileid = -1;
|
||||||
|
photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||||
createdby = user.CreatedBy;
|
createdby = user.CreatedBy;
|
||||||
createdon = user.CreatedOn;
|
createdon = user.CreatedOn;
|
||||||
|
@ -200,11 +206,10 @@ else
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
photofileid = filemanager.GetFileId();
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
|
if (user.PhotoFileId == -1)
|
||||||
if (photofileid != -1)
|
|
||||||
{
|
{
|
||||||
user.PhotoFileId = photofileid;
|
user.PhotoFileId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
private string _filter = "*";
|
private string _filter = "*";
|
||||||
private bool _haseditpermission = false;
|
private bool _haseditpermission = false;
|
||||||
private string _image = string.Empty;
|
private string _image = string.Empty;
|
||||||
|
private File _file = null;
|
||||||
private string _guid;
|
private string _guid;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private MessageType _messagetype;
|
private MessageType _messagetype;
|
||||||
|
@ -199,6 +200,7 @@
|
||||||
FolderId = int.Parse((string)e.Value);
|
FolderId = int.Parse((string)e.Value);
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
FileId = -1;
|
FileId = -1;
|
||||||
|
_file = null;
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
@ -223,21 +225,22 @@
|
||||||
private async Task SetImage()
|
private async Task SetImage()
|
||||||
{
|
{
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
|
_file = null;
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
File file = await FileService.GetFileAsync(FileId);
|
_file = await FileService.GetFileAsync(FileId);
|
||||||
if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0)
|
if (_file != null && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
||||||
{
|
{
|
||||||
var maxwidth = 200;
|
var maxwidth = 200;
|
||||||
var maxheight = 200;
|
var maxheight = 200;
|
||||||
|
|
||||||
var ratioX = (double)maxwidth / (double)file.ImageWidth;
|
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
||||||
var ratioY = (double)maxheight / (double)file.ImageHeight;
|
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
||||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||||
|
|
||||||
_image = "<img src=\"" + ContentUrl(FileId) + "\" alt=\"" + file.Name +
|
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
||||||
"\" width=\"" + Convert.ToInt32(file.ImageWidth * ratio).ToString() +
|
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
||||||
"\" height=\"" + Convert.ToInt32(file.ImageHeight * ratio).ToString() + "\" />";
|
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,4 +334,5 @@
|
||||||
|
|
||||||
public int GetFileId() => FileId;
|
public int GetFileId() => FileId;
|
||||||
|
|
||||||
|
public File GetFile() => _file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,11 +191,11 @@
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
if (_filemanagervisible)
|
if (_filemanagervisible)
|
||||||
{
|
{
|
||||||
var fileid = _fileManager.GetFileId();
|
var file = _fileManager.GetFile();
|
||||||
if (fileid != -1)
|
if (file != null)
|
||||||
{
|
{
|
||||||
var interop = new RichTextEditorInterop(JSRuntime);
|
var interop = new RichTextEditorInterop(JSRuntime);
|
||||||
await interop.InsertImage(_editorElement, ContentUrl(fileid));
|
await interop.InsertImage(_editorElement, file.Url, file.Name);
|
||||||
_filemanagervisible = false;
|
_filemanagervisible = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using System.Threading.Tasks;
|
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
|
try
|
||||||
{
|
{
|
||||||
_jsRuntime.InvokeAsync<object>(
|
_jsRuntime.InvokeAsync<object>(
|
||||||
"Oqtane.RichTextEditor.insertQuillImage",
|
"Oqtane.RichTextEditor.insertQuillImage",
|
||||||
quillElement, imageUrl);
|
quillElement, imageUrl, altText);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
_content = htmltext.Content;
|
_content = htmltext.Content;
|
||||||
_content = _content.Replace(Constants.ContentUrl, Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl));
|
_content = Utilities.FormatContent(_content, PageState.Alias, "render");
|
||||||
_createdby = htmltext.CreatedBy;
|
_createdby = htmltext.CreatedBy;
|
||||||
_createdon = htmltext.CreatedOn;
|
_createdon = htmltext.CreatedOn;
|
||||||
_modifiedby = htmltext.ModifiedBy;
|
_modifiedby = htmltext.ModifiedBy;
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
private async Task SaveContent()
|
private async Task SaveContent()
|
||||||
{
|
{
|
||||||
string content = await RichTextEditorHtml.GetHtml();
|
string content = await RichTextEditorHtml.GetHtml();
|
||||||
content = content.Replace(Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl), Constants.ContentUrl);
|
content = Utilities.FormatContent(content, PageState.Alias, "save");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
content = htmltext.Content;
|
content = htmltext.Content;
|
||||||
content = content.Replace(Constants.ContentUrl, Utilities.TenantUrl(PageState.Alias, Constants.ContentUrl));
|
content = Utilities.FormatContent(content, PageState.Alias, "render");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -1,12 +1,24 @@
|
||||||
@namespace Oqtane.Themes.Controls
|
@namespace Oqtane.Themes.Controls
|
||||||
@inherits ThemeControlBase
|
@inherits ThemeControlBase
|
||||||
|
@inject IFileService FileService
|
||||||
|
|
||||||
@if (PageState.Site.LogoFileId != null)
|
@if (file != null)
|
||||||
{
|
{
|
||||||
<span class="app-logo">
|
<span class="app-logo">
|
||||||
<a href="@PageState.Alias.Path">
|
<a href="@PageState.Alias.Path">
|
||||||
<img class="img-fluid" src="@ContentUrl(PageState.Site.LogoFileId.Value)" alt="@PageState.Site.Name" />
|
<img class="img-fluid" src="@file.Url" alt="@PageState.Site.Name" />
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -173,6 +173,7 @@ namespace Oqtane.Controllers
|
||||||
SiteId = folder.SiteId,
|
SiteId = folder.SiteId,
|
||||||
ParentId = folder.FolderId,
|
ParentId = folder.FolderId,
|
||||||
Name = "My Folder",
|
Name = "My Folder",
|
||||||
|
Type = FolderTypes.Private,
|
||||||
Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),Path.DirectorySeparatorChar.ToString()),
|
Path = Utilities.PathCombine(folder.Path, newUser.UserId.ToString(),Path.DirectorySeparatorChar.ToString()),
|
||||||
Order = 1,
|
Order = 1,
|
||||||
IsSystem = true,
|
IsSystem = true,
|
||||||
|
|
|
@ -593,6 +593,7 @@ namespace Oqtane.Infrastructure
|
||||||
SiteId = folder.SiteId,
|
SiteId = folder.SiteId,
|
||||||
ParentId = folder.FolderId,
|
ParentId = folder.FolderId,
|
||||||
Name = "My Folder",
|
Name = "My Folder",
|
||||||
|
Type = FolderTypes.Private,
|
||||||
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
||||||
Order = 1,
|
Order = 1,
|
||||||
IsSystem = true,
|
IsSystem = true,
|
||||||
|
|
|
@ -231,7 +231,6 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||||
public void DeleteFromTable(string condition = "")
|
public void DeleteFromTable(string condition = "")
|
||||||
{
|
{
|
||||||
var deleteSql = $"DELETE FROM {RewriteName(EntityTableName)} ";
|
var deleteSql = $"DELETE FROM {RewriteName(EntityTableName)} ";
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(condition))
|
if(!string.IsNullOrEmpty(condition))
|
||||||
{
|
{
|
||||||
deleteSql += $"WHERE {condition}";
|
deleteSql += $"WHERE {condition}";
|
||||||
|
@ -241,10 +240,7 @@ namespace Oqtane.Migrations.EntityBuilders
|
||||||
|
|
||||||
public void UpdateColumn(string columnName, string value, string condition = "")
|
public void UpdateColumn(string columnName, string value, string condition = "")
|
||||||
{
|
{
|
||||||
var updateValue = value;
|
|
||||||
|
|
||||||
var updateSql = $"UPDATE {RewriteName(EntityTableName)} SET {RewriteName(columnName)} = {value} ";
|
var updateSql = $"UPDATE {RewriteName(EntityTableName)} SET {RewriteName(columnName)} = {value} ";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(condition))
|
if (!string.IsNullOrEmpty(condition))
|
||||||
{
|
{
|
||||||
updateSql += $"WHERE {condition}";
|
updateSql += $"WHERE {condition}";
|
||||||
|
|
34
Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs
Normal file
34
Oqtane.Server/Migrations/Tenant/02010003_AddFolderType.cs
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using File = Oqtane.Models.File;
|
using File = Oqtane.Models.File;
|
||||||
|
@ -14,21 +15,25 @@ namespace Oqtane.Repository
|
||||||
private TenantDBContext _db;
|
private TenantDBContext _db;
|
||||||
private readonly IPermissionRepository _permissions;
|
private readonly IPermissionRepository _permissions;
|
||||||
private readonly IFolderRepository _folderRepository;
|
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;
|
_db = context;
|
||||||
_permissions = permissions;
|
_permissions = permissions;
|
||||||
_folderRepository = folderRepository;
|
_folderRepository = folderRepository;
|
||||||
|
_tenants = tenants;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<File> GetFiles(int folderId)
|
public IEnumerable<File> GetFiles(int folderId)
|
||||||
{
|
{
|
||||||
IEnumerable<Permission> permissions = _permissions.GetPermissions(EntityNames.Folder, folderId).ToList();
|
IEnumerable<Permission> permissions = _permissions.GetPermissions(EntityNames.Folder, folderId).ToList();
|
||||||
IEnumerable<File> files = _db.File.Where(item => item.FolderId == folderId).Include(item => item.Folder);
|
IEnumerable<File> files = _db.File.Where(item => item.FolderId == folderId).Include(item => item.Folder);
|
||||||
|
var alias = _tenants.GetAlias();
|
||||||
foreach (File file in files)
|
foreach (File file in files)
|
||||||
{
|
{
|
||||||
file.Folder.Permissions = permissions.EncodePermissions();
|
file.Folder.Permissions = permissions.EncodePermissions();
|
||||||
|
file.Url = GetFileUrl(file, alias);
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
@ -49,7 +54,9 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
public File GetFile(int fileId)
|
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)
|
public File GetFile(int fileId, bool tracking)
|
||||||
|
@ -68,6 +75,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
IEnumerable<Permission> permissions = _permissions.GetPermissions(EntityNames.Folder, file.FolderId).ToList();
|
IEnumerable<Permission> permissions = _permissions.GetPermissions(EntityNames.Folder, file.FolderId).ToList();
|
||||||
file.Folder.Permissions = permissions.EncodePermissions();
|
file.Folder.Permissions = permissions.EncodePermissions();
|
||||||
|
file.Url = GetFileUrl(file, _tenants.GetAlias());
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -92,5 +100,20 @@ namespace Oqtane.Repository
|
||||||
var filepath = Path.Combine(_folderRepository.GetFolderPath(folder), file.Name);
|
var filepath = Path.Combine(_folderRepository.GetFolderPath(folder), file.Name);
|
||||||
return filepath;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
@ -13,9 +14,9 @@ namespace Oqtane.Repository
|
||||||
private TenantDBContext _db;
|
private TenantDBContext _db;
|
||||||
private readonly IPermissionRepository _permissions;
|
private readonly IPermissionRepository _permissions;
|
||||||
private readonly IWebHostEnvironment _environment;
|
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;
|
_db = context;
|
||||||
_permissions = permissions;
|
_permissions = permissions;
|
||||||
|
@ -99,7 +100,17 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
public string GetFolderPath(Folder folder)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -648,25 +648,25 @@ namespace Oqtane.Repository
|
||||||
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true});
|
_roleRepository.AddRole(new Role {SiteId = site.SiteId, Name = RoleNames.Admin, Description = "Site Administrators", IsAutoAssigned = false, IsSystem = true});
|
||||||
|
|
||||||
_profileRepository.AddProfile(new Profile
|
_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
|
_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
|
_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(
|
_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
|
_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
|
_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
|
_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
|
_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
|
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<Permission>
|
Permissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.Browse, RoleNames.Admin, true),
|
new Permission(PermissionNames.Browse, RoleNames.Admin, true),
|
||||||
|
@ -676,7 +676,7 @@ namespace Oqtane.Repository
|
||||||
});
|
});
|
||||||
_folderRepository.AddFolder(new Folder
|
_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<Permission>
|
Permissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.Browse, RoleNames.Admin, true),
|
new Permission(PermissionNames.Browse, RoleNames.Admin, true),
|
||||||
|
|
|
@ -35,7 +35,7 @@ Oqtane.RichTextEditor = {
|
||||||
enableQuillEditor: function (editorElement, mode) {
|
enableQuillEditor: function (editorElement, mode) {
|
||||||
editorElement.__quill.enable(mode);
|
editorElement.__quill.enable(mode);
|
||||||
},
|
},
|
||||||
insertQuillImage: function (quillElement, imageURL) {
|
insertQuillImage: function (quillElement, imageURL, altText) {
|
||||||
var Delta = Quill.import('delta');
|
var Delta = Quill.import('delta');
|
||||||
editorIndex = 0;
|
editorIndex = 0;
|
||||||
|
|
||||||
|
@ -47,6 +47,6 @@ Oqtane.RichTextEditor = {
|
||||||
new Delta()
|
new Delta()
|
||||||
.retain(editorIndex)
|
.retain(editorIndex)
|
||||||
.insert({ image: imageURL },
|
.insert({ image: imageURL },
|
||||||
{ alt: imageURL }));
|
{ alt: altText }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Models
|
namespace Oqtane.Models
|
||||||
{
|
{
|
||||||
|
@ -78,5 +80,11 @@ namespace Oqtane.Models
|
||||||
/// TODO: not sure if this is always populated, must verify and document
|
/// TODO: not sure if this is always populated, must verify and document
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Folder Folder { get; set; }
|
public Folder Folder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// url for accessing file
|
||||||
|
/// </summary>
|
||||||
|
[NotMapped]
|
||||||
|
public string Url { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ namespace Oqtane.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int? ParentId { get; set; }
|
public int? ParentId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Folder type - based on FolderTypes
|
||||||
|
/// </summary>
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Folder name
|
/// Folder name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
6
Oqtane.Shared/Shared/FolderTypes.cs
Normal file
6
Oqtane.Shared/Shared/FolderTypes.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Oqtane.Shared {
|
||||||
|
public class FolderTypes {
|
||||||
|
public const string Private = "Private";
|
||||||
|
public const string Public = "Public";
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,6 +113,23 @@ namespace Oqtane.Shared
|
||||||
url = (!url.StartsWith("/")) ? "/" + url : url;
|
url = (!url.StartsWith("/")) ? "/" + url : url;
|
||||||
return (alias != null && !string.IsNullOrEmpty(alias.Path)) ? "/" + alias.Path + 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)
|
public static string GetTypeName(string fullyqualifiedtypename)
|
||||||
{
|
{
|
||||||
if (fullyqualifiedtypename.Contains(","))
|
if (fullyqualifiedtypename.Contains(","))
|
||||||
|
@ -325,6 +342,11 @@ namespace Oqtane.Shared
|
||||||
return Path.Combine(segments).TrimEnd();
|
return Path.Combine(segments).TrimEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string UrlCombine(params string[] segments)
|
||||||
|
{
|
||||||
|
return string.Join("/", segments);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsPathValid(this Folder folder)
|
public static bool IsPathValid(this Folder folder)
|
||||||
{
|
{
|
||||||
return IsPathOrFileValid(folder.Name);
|
return IsPathOrFileValid(folder.Name);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user