✨ Managed mode page will render with layout
This commit is contained in:
@@ -30,7 +30,6 @@ public class PublicationSiteNavItem
|
||||
{
|
||||
[MaxLength(1024)] public string Label { get; set; } = null!;
|
||||
[MaxLength(8192)] public string Href { get; set; } = null!;
|
||||
Dictionary<string, object> Attributes { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SnPublicationSite : ModelBase
|
||||
|
||||
8
DysonNetwork.Zone/Pages/Dynamic/DynamicPage.cshtml
Normal file
8
DysonNetwork.Zone/Pages/Dynamic/DynamicPage.cshtml
Normal file
@@ -0,0 +1,8 @@
|
||||
@model DynamicPage
|
||||
@{
|
||||
Layout = "_LayoutContained";
|
||||
}
|
||||
|
||||
<div class="dynamic-content">
|
||||
@Html.Raw(Model.Html)
|
||||
</div>
|
||||
8
DysonNetwork.Zone/Pages/Dynamic/DynamicPage.cshtml.cs
Normal file
8
DysonNetwork.Zone/Pages/Dynamic/DynamicPage.cshtml.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace DysonNetwork.Zone.Pages.Dynamic;
|
||||
|
||||
public class DynamicPage : PageModel
|
||||
{
|
||||
public string Html { get; set; } = "";
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@using DysonNetwork.Zone.Publication
|
||||
@using DysonNetwork.Shared.Models
|
||||
@using Microsoft.IdentityModel.Tokens
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
var site = Context.Items[PublicationSiteMiddleware.SiteContextKey] as SnPublicationSite;
|
||||
@@ -8,13 +9,26 @@
|
||||
|
||||
<div class="navbar backdrop-blur-md bg-white/1 shadow-xl px-5">
|
||||
<div class="flex-1">
|
||||
<a class="btn btn-ghost text-xl" asp-page="/Index">@siteDisplayName</a>
|
||||
<a class="btn btn-ghost text-xl" href="/">@siteDisplayName</a>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a asp-page="/Posts">Posts</a></li>
|
||||
<li><a asp-page="/About">About</a></li>
|
||||
</ul>
|
||||
@if (site?.Config.NavItems is null || site.Config.NavItems.IsNullOrEmpty())
|
||||
{
|
||||
@*Use preset navs*@
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a href="/posts">Posts</a></li>
|
||||
<li><a href="/about">About</a></li>
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
@foreach (var item in site.Config.NavItems)
|
||||
{
|
||||
<li><a href="@item.Href">@item.Label</a></li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,6 +44,11 @@
|
||||
@section Head
|
||||
{
|
||||
@await RenderSectionAsync("Head", required: false)
|
||||
|
||||
@if (site?.Config.StyleOverride is not null)
|
||||
{
|
||||
<style>@(site.Config.StyleOverride)</style>
|
||||
}
|
||||
|
||||
<style>
|
||||
.navbar {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Zone.Pages.Dynamic;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -8,8 +16,14 @@ namespace DysonNetwork.Zone.Publication;
|
||||
public class PublicationSiteMiddleware(RequestDelegate next)
|
||||
{
|
||||
public const string SiteContextKey = "PubSite";
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, AppDatabase db, PublicationSiteManager psm)
|
||||
|
||||
public async Task InvokeAsync(
|
||||
HttpContext context,
|
||||
AppDatabase db,
|
||||
PublicationSiteManager psm,
|
||||
IRazorViewEngine viewEngine,
|
||||
ITempDataProvider tempData
|
||||
)
|
||||
{
|
||||
var siteNameValue = context.Request.Headers["X-SiteName"].ToString();
|
||||
var currentPath = context.Request.Path.Value ?? "";
|
||||
@@ -21,7 +35,8 @@ public class PublicationSiteMiddleware(RequestDelegate next)
|
||||
}
|
||||
|
||||
var site = await db.PublicationSites
|
||||
.FirstOrDefaultAsync(s => EF.Functions.ILike(s.Slug, siteNameValue));
|
||||
.FirstOrDefaultAsync(s => EF.Functions.ILike(s.Slug, siteNameValue)
|
||||
);
|
||||
if (site == null)
|
||||
{
|
||||
await next(context);
|
||||
@@ -29,7 +44,7 @@ public class PublicationSiteMiddleware(RequestDelegate next)
|
||||
}
|
||||
|
||||
context.Items[SiteContextKey] = site;
|
||||
|
||||
|
||||
var page = await db.PublicationPages
|
||||
.FirstOrDefaultAsync(p => p.SiteId == site.Id && p.Path == currentPath);
|
||||
if (page != null)
|
||||
@@ -38,13 +53,31 @@ public class PublicationSiteMiddleware(RequestDelegate next)
|
||||
{
|
||||
case PublicationPageType.HtmlPage
|
||||
when page.Config.TryGetValue("html", out var html) && html is JsonElement content:
|
||||
context.Response.ContentType = "text/html";
|
||||
await context.Response.WriteAsync(content.ToString());
|
||||
if (site.Mode == PublicationSiteMode.FullyManaged)
|
||||
{
|
||||
context.Items["PublicationHtmlContent"] = content.ToString();
|
||||
var layoutedHtml = await RenderViewAsync(
|
||||
context,
|
||||
viewEngine,
|
||||
tempData,
|
||||
"/Pages/Dynamic/DynamicPage.cshtml",
|
||||
new DynamicPage { Html = content.ToString() }
|
||||
);
|
||||
context.Response.ContentType = "text/html";
|
||||
await context.Response.WriteAsync(layoutedHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.ContentType = "text/html";
|
||||
await context.Response.WriteAsync(content.ToString());
|
||||
}
|
||||
return;
|
||||
case PublicationPageType.Redirect
|
||||
when page.Config.TryGetValue("target", out var tgt) && tgt is JsonElement redirectUrl:
|
||||
context.Response.Redirect(redirectUrl.ToString());
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,4 +118,51 @@ public class PublicationSiteMiddleware(RequestDelegate next)
|
||||
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> RenderViewAsync(
|
||||
HttpContext context,
|
||||
IRazorViewEngine engine,
|
||||
ITempDataProvider tempDataProvider,
|
||||
string viewPath,
|
||||
object model)
|
||||
{
|
||||
var endpointFeature = context.Features.Get<IEndpointFeature>();
|
||||
var endpoint = endpointFeature?.Endpoint;
|
||||
|
||||
var routeData = context.GetRouteData();
|
||||
|
||||
var actionContext = new ActionContext(
|
||||
context,
|
||||
routeData,
|
||||
new ActionDescriptor()
|
||||
);
|
||||
|
||||
await using var sw = new StringWriter();
|
||||
|
||||
var viewResult = engine.GetView(null, viewPath, true);
|
||||
|
||||
if (!viewResult.Success)
|
||||
throw new FileNotFoundException($"View '{viewPath}' not found.");
|
||||
|
||||
var viewData = new ViewDataDictionary(
|
||||
new EmptyModelMetadataProvider(),
|
||||
new ModelStateDictionary())
|
||||
{
|
||||
Model = model
|
||||
};
|
||||
|
||||
var tempData = new TempDataDictionary(context, tempDataProvider);
|
||||
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
viewResult.View,
|
||||
viewData,
|
||||
tempData,
|
||||
sw,
|
||||
new HtmlHelperOptions()
|
||||
);
|
||||
|
||||
await viewResult.View.RenderAsync(viewContext);
|
||||
return sw.ToString();
|
||||
}
|
||||
}
|
||||
@@ -122,6 +122,8 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOk_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F01d30b32e2ff422cb80129ca2a441c4242600_003F3b_003F237bf104_003FOk_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOpenApiInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ffcedb617b237dc31e998d31e01f101e8441948433938518c5f20cec1a845c1_003FOpenApiInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOptionsConfigurationServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6622dea924b14dc7aa3ee69d7c84e5735000_003Fe0_003F024ba0b7_003FOptionsConfigurationServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APageActionDescriptor_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2be344df4d74430c8cfa6e1fd83191ea7b110_003Fc2_003F5bba515a_003FPageActionDescriptor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APageLoader_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2be344df4d74430c8cfa6e1fd83191ea7b110_003F9e_003Ff8e508b5_003FPageLoader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APageModel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2be344df4d74430c8cfa6e1fd83191ea7b110_003Ff3_003Fd92c30ee_003FPageModel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APathStringTransform_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003Fc5_003Fc4220f9f_003FPathStringTransform_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APathTransformExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003Fd9_003Faff65774_003FPathTransformExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
@@ -155,6 +157,9 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASourceCustom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fdaa8d9c408cd4b4286bbef7e35f1a42e31c00_003F45_003F5839ca6c_003FSourceCustom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3bef61b8a21d4c8e96872ecdd7782fa0e55000_003F7a_003F870020d0_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fdf_003F3fcdc4d2_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodePagesExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffe98808dec0c44c18de3f97b316370d478f08_003F20_003F1750deb2_003FStatusCodePagesExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodePagesMiddleware_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffe98808dec0c44c18de3f97b316370d478f08_003F0b_003Ff955e54b_003FStatusCodePagesMiddleware_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodePagesOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffe98808dec0c44c18de3f97b316370d478f08_003F01_003F859257a9_003FStatusCodePagesOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodeResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F7c_003F8b7572ae_003FStatusCodeResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStreamConfig_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7140aa4493a2490fb306b1e68b5d533c98200_003Fbc_003Fccf922ff_003FStreamConfig_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStructuredTransformer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F5c_003F73acd7b4_003FStructuredTransformer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
Reference in New Issue
Block a user