Merge pull request #6069 from sbwalker/dev
add copy page functionality to control panel
This commit is contained in:
@@ -46,7 +46,7 @@
|
|||||||
<Label Class="col-sm-3" For="move" HelpText="Select the location where you would like the page to be moved in relation to other pages" ResourceKey="Move">Move: </Label>
|
<Label Class="col-sm-3" For="move" HelpText="Select the location where you would like the page to be moved in relation to other pages" ResourceKey="Move">Move: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="move" class="form-select" @bind="@_insert" required>
|
<select id="move" class="form-select" @bind="@_insert" required>
|
||||||
@if (_parentid == _currentparentid)
|
@if (_parentid == _currentparentid && !_copy)
|
||||||
{
|
{
|
||||||
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
||||||
}
|
}
|
||||||
@@ -247,6 +247,8 @@
|
|||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
@if (!_copy)
|
||||||
|
{
|
||||||
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
||||||
<Pager Items="_pageModules">
|
<Pager Items="_pageModules">
|
||||||
<Header>
|
<Header>
|
||||||
@@ -272,6 +274,8 @@
|
|||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -349,6 +353,7 @@
|
|||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
|
private bool _copy = false;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _currentparentid;
|
private string _currentparentid;
|
||||||
private string _parentid = "-1";
|
private string _parentid = "-1";
|
||||||
@@ -394,6 +399,10 @@
|
|||||||
{
|
{
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
|
if (PageState.QueryString.ContainsKey("copy"))
|
||||||
|
{
|
||||||
|
_copy = bool.Parse(PageState.QueryString["copy"]);
|
||||||
|
}
|
||||||
_page = await PageService.GetPageAsync(_pageId);
|
_page = await PageService.GetPageAsync(_pageId);
|
||||||
_icons = await SystemService.GetIconsAsync();
|
_icons = await SystemService.GetIconsAsync();
|
||||||
_iconresources = Utilities.GetFullTypeName(typeof(IconResources).AssemblyQualifiedName);
|
_iconresources = Utilities.GetFullTypeName(typeof(IconResources).AssemblyQualifiedName);
|
||||||
@@ -413,7 +422,7 @@
|
|||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
||||||
{
|
{
|
||||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if ((p.PageId != _pageId || _copy) && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@@ -440,6 +449,12 @@
|
|||||||
_expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate);
|
_expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate);
|
||||||
_ispersonalizable = _page.IsPersonalizable.ToString();
|
_ispersonalizable = _page.IsPersonalizable.ToString();
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_insert = ">";
|
||||||
|
_childid = _page.PageId;
|
||||||
|
}
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
_title = _page.Title;
|
_title = _page.Title;
|
||||||
_themetype = _page.ThemeType;
|
_themetype = _page.ThemeType;
|
||||||
@@ -470,6 +485,19 @@
|
|||||||
// permissions
|
// permissions
|
||||||
_permissions = _page.PermissionList;
|
_permissions = _page.PermissionList;
|
||||||
_updatemodulepermissions = "True";
|
_updatemodulepermissions = "True";
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_permissions = _page.PermissionList.Select(item => new Permission
|
||||||
|
{
|
||||||
|
SiteId = item.SiteId,
|
||||||
|
EntityName = item.EntityName,
|
||||||
|
EntityId = -1,
|
||||||
|
PermissionName = item.PermissionName,
|
||||||
|
RoleName = item.RoleName,
|
||||||
|
UserId = item.UserId,
|
||||||
|
IsAuthorized = item.IsAuthorized,
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
// page modules
|
// page modules
|
||||||
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
@@ -484,6 +512,13 @@
|
|||||||
_deletedon = _page.DeletedOn;
|
_deletedon = _page.DeletedOn;
|
||||||
|
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_name = "";
|
||||||
|
_path = "";
|
||||||
|
}
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -581,6 +616,13 @@
|
|||||||
{
|
{
|
||||||
string currentPath = _page.Path;
|
string currentPath = _page.Path;
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_page = new Page();
|
||||||
|
_page.SiteId = PageState.Site.SiteId;
|
||||||
|
currentPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
_page.Name = _name;
|
_page.Name = _name;
|
||||||
|
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
@@ -696,8 +738,19 @@
|
|||||||
_page.UpdateModulePermissions = bool.Parse(_updatemodulepermissions);
|
_page.UpdateModulePermissions = bool.Parse(_updatemodulepermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
// create page
|
||||||
|
_page = await PageService.AddPageAsync(_page);
|
||||||
|
await PageService.CopyPageAsync(_pageId, _page.PageId, bool.Parse(_updatemodulepermissions));
|
||||||
|
await logger.LogInformation("Page Added {Page}", _page);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// update page
|
// update page
|
||||||
_page = await PageService.UpdatePageAsync(_page);
|
_page = await PageService.UpdatePageAsync(_page);
|
||||||
|
await logger.LogInformation("Page Saved {Page}", _page);
|
||||||
|
}
|
||||||
|
|
||||||
// update page order
|
// update page order
|
||||||
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, _page.ParentId);
|
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, _page.ParentId);
|
||||||
@@ -710,7 +763,6 @@
|
|||||||
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, int.Parse(_currentparentid));
|
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, int.Parse(_currentparentid));
|
||||||
}
|
}
|
||||||
|
|
||||||
await logger.LogInformation("Page Saved {Page}", _page);
|
|
||||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
||||||
|
|||||||
@@ -201,4 +201,7 @@
|
|||||||
<data name="Synchronize" xml:space="preserve">
|
<data name="Synchronize" xml:space="preserve">
|
||||||
<value>Synchronize Site</value>
|
<value>Synchronize Site</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Copy" xml:space="preserve">
|
||||||
|
<value>Copy Page</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -71,6 +71,15 @@ namespace Oqtane.Services
|
|||||||
/// <param name="pageId"></param>
|
/// <param name="pageId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task DeletePageAsync(int pageId);
|
Task DeletePageAsync(int pageId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the modules from one page to another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromPageId"></param>
|
||||||
|
/// <param name="toPageId"></param>
|
||||||
|
/// <param name="usePagePermissions"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task CopyPageAsync(int fromPageId, int toPageId, bool usePagePermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
@@ -129,5 +138,10 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
await DeleteAsync($"{Apiurl}/{pageId}");
|
await DeleteAsync($"{Apiurl}/{pageId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CopyPageAsync(int fromPageId, int toPageId, bool usePagePermissions)
|
||||||
|
{
|
||||||
|
await PostAsync($"{Apiurl}/{fromPageId}/{toPageId}/{usePagePermissions}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,16 @@
|
|||||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (PageState.Page.UserId == null)
|
||||||
|
{
|
||||||
|
<div class="row d-flex mb-2">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="btn btn-secondary col-12" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Copy"))>@Localizer["Copy"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (!PageState.Page.Path.StartsWith("admin/"))
|
||||||
|
{
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
@if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
@@ -71,6 +81,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
|
|
||||||
@if (_deleteConfirmation)
|
@if (_deleteConfirmation)
|
||||||
@@ -496,7 +507,12 @@
|
|||||||
case "Edit":
|
case "Edit":
|
||||||
// get page management moduleid
|
// get page management moduleid
|
||||||
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
||||||
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, "Edit", $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
||||||
|
break;
|
||||||
|
case "Copy":
|
||||||
|
// get page management moduleid
|
||||||
|
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
||||||
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, "Edit", $"id={PageState.Page.PageId}©=true&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Oqtane.Security;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using System.Xml.Linq;
|
using Oqtane.Security;
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@@ -498,6 +497,79 @@ namespace Oqtane.Controllers
|
|||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/5/6
|
||||||
|
[HttpPost("{fromPageId}/{toPageId}/{usePagePermissions}")]
|
||||||
|
[Authorize(Roles = RoleNames.Registered)]
|
||||||
|
public void Post(int fromPageId, int toPageId, bool usePagePermissions)
|
||||||
|
{
|
||||||
|
var fromPage = _pages.GetPage(fromPageId);
|
||||||
|
if (fromPage != null && fromPage.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, fromPage.PermissionList))
|
||||||
|
{
|
||||||
|
var toPage = _pages.GetPage(toPageId);
|
||||||
|
if (toPage != null && toPage.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, toPage.PermissionList))
|
||||||
|
{
|
||||||
|
// copy modules
|
||||||
|
List<PageModule> pageModules = _pageModules.GetPageModules(fromPage.SiteId).ToList();
|
||||||
|
foreach (PageModule pm in pageModules.Where(item => item.PageId == fromPage.PageId && !item.Module.AllPages && !item.IsDeleted))
|
||||||
|
{
|
||||||
|
Module module = new Module();
|
||||||
|
module.SiteId = fromPage.SiteId;
|
||||||
|
module.PageId = toPageId;
|
||||||
|
module.ModuleDefinitionName = pm.Module.ModuleDefinitionName;
|
||||||
|
module.AllPages = false;
|
||||||
|
if (usePagePermissions)
|
||||||
|
{
|
||||||
|
module.PermissionList = toPage.PermissionList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module.PermissionList = pm.Module.PermissionList;
|
||||||
|
}
|
||||||
|
module.PermissionList = module.PermissionList.Select(item => new Permission
|
||||||
|
{
|
||||||
|
SiteId = item.SiteId,
|
||||||
|
EntityName = EntityNames.Module,
|
||||||
|
EntityId = -1,
|
||||||
|
PermissionName = item.PermissionName,
|
||||||
|
RoleName = item.RoleName,
|
||||||
|
UserId = item.UserId,
|
||||||
|
IsAuthorized = item.IsAuthorized,
|
||||||
|
}).ToList();
|
||||||
|
module = _modules.AddModule(module);
|
||||||
|
|
||||||
|
string content = _modules.ExportModule(pm.ModuleId);
|
||||||
|
if (content != "")
|
||||||
|
{
|
||||||
|
_modules.ImportModule(module.ModuleId, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PageModule pageModule = new PageModule();
|
||||||
|
pageModule.PageId = toPageId;
|
||||||
|
pageModule.ModuleId = module.ModuleId;
|
||||||
|
pageModule.Title = pm.Title;
|
||||||
|
pageModule.Pane = pm.Pane;
|
||||||
|
pageModule.Order = pm.Order;
|
||||||
|
pageModule.ContainerType = pm.ContainerType;
|
||||||
|
pageModule.EffectiveDate = pm.EffectiveDate;
|
||||||
|
pageModule.ExpiryDate = pm.ExpiryDate;
|
||||||
|
pageModule.Header = pm.Header;
|
||||||
|
pageModule.Footer = pm.Footer;
|
||||||
|
|
||||||
|
_pageModules.AddPageModule(pageModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, fromPage.SiteId, SyncEventActions.Refresh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
// synchronization only supports sites in the same tenant (database)
|
// synchronization only supports sites in the same tenant (database)
|
||||||
// module title is used as a key to identify module instances on a page
|
// module title is used as a key to identify module instances on a page
|
||||||
// modules must implement ISynchronizable interface
|
// modules must implement ISynchronizable interface for content synchronization
|
||||||
// change detection does not support deleted items as key values will usually be different due to localization
|
// change detection does not support deleted items as key values will usually be different due to localization
|
||||||
|
|
||||||
// define settings that should not be synchronized (should be extensible in the future)
|
// define settings that should not be synchronized (should be extensible in the future)
|
||||||
|
|||||||
Reference in New Issue
Block a user