Render self-managed site

This commit is contained in:
2025-11-21 01:55:22 +08:00
parent cad72502d9
commit 7016a0a943
6 changed files with 45 additions and 22 deletions

View File

@@ -1,6 +1,7 @@
# dependencies (bun install)
node_modules
wwwroot/css/site.dist.css
wwwroot/SiteData
# output
out
@@ -33,5 +34,3 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Finder (MacOS) folder config
.DS_Store
SiteData

View File

@@ -16,7 +16,8 @@
haven't configure anything that match this route.
</p>
<div class="text-xs opacity-70 mt-1">
<p>Path: <b>@Model.CurrentPath</b> Site ID: <b>@(Model.Site?.Id.ToString() ?? "none")</b></p>
<p>Path: <b>@Model.CurrentPath</b></p>
<p>Site ID: <b>@(Model.Site?.Id.ToString() ?? "none")</b></p>
</div>
</div>
</div>

View File

@@ -1,13 +1,14 @@
using DysonNetwork.Shared.Models;
using DysonNetwork.Zone.Publication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using System.IO;
using System.Text.Json;
namespace DysonNetwork.Zone.Pages;
public class IndexModel(AppDatabase db) : PageModel
public class IndexModel(AppDatabase db, PublicationSiteManager psm) : PageModel
{
public SnPublicationSite? Site { get; set; }
public string? SiteName { get; set; }
@@ -21,25 +22,46 @@ public class IndexModel(AppDatabase db) : PageModel
if (string.IsNullOrEmpty(siteNameValue))
{
SiteName = null;
return Page();
}
else
{
var capturedName = siteNameValue;
Site = await db.PublicationSites.FirstOrDefaultAsync(s => s.Slug == capturedName);
if (Site == null) return Page();
var pagePath = CurrentPath;
var page = await db.PublicationPages.FirstOrDefaultAsync(p => p.SiteId == Site.Id && p.Path == pagePath);
if (page == null) return Page();
var capturedName = siteNameValue;
Site = await db.PublicationSites.FirstOrDefaultAsync(s => s.Slug == capturedName);
if (Site == null) return Page();
var pagePath = CurrentPath;
var page = await db.PublicationPages.FirstOrDefaultAsync(p => p.SiteId == Site.Id && p.Path == pagePath);
if (page != null)
{
switch (page.Type)
{
case PublicationPageType.HtmlPage when page.Config.TryGetValue("html", out var html) && html is JsonElement content:
case PublicationPageType.HtmlPage
when page.Config.TryGetValue("html", out var html) && html is JsonElement content:
return Content(content.ToString(), "text/html");
case PublicationPageType.Redirect when page.Config.TryGetValue("url", out var url) && url is JsonElement redirectUrl:
case PublicationPageType.Redirect
when page.Config.TryGetValue("url", out var url) && url is JsonElement redirectUrl:
return Redirect(redirectUrl.ToString());
}
}
// If the site is enabled the self-managed mode, try lookup the files then
if (Site.Mode == PublicationSiteMode.SelfManaged)
{
// TODO: Fix the path contains a wwwroot
var provider = new FileExtensionContentTypeProvider();
var hostedFilePath = psm.GetValidatedFullPath(Site.Id, CurrentPath);
if (System.IO.File.Exists(hostedFilePath))
{
if (!provider.TryGetContentType(hostedFilePath, out var mimeType))
mimeType = "text/html";
return File(hostedFilePath, mimeType);
}
var hostedNotFoundPath = psm.GetValidatedFullPath(Site.Id, "404.html");
if (System.IO.File.Exists(hostedNotFoundPath))
return File(hostedNotFoundPath, "text/html");
}
return Page();
}
}
}

View File

@@ -25,10 +25,10 @@ public class PublicationSiteManager(
{
// Treat paths starting with separator as relative to site root
relativePath = relativePath.TrimStart('/', '\\');
string fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath);
string normalizedPath = Path.GetFullPath(fullPath);
string siteDirFull = Path.Combine(_basePath, siteId.ToString());
string normalizedSiteDir = Path.GetFullPath(siteDirFull);
var fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath);
var normalizedPath = Path.GetFullPath(fullPath);
var siteDirFull = Path.Combine(_basePath, siteId.ToString());
var normalizedSiteDir = Path.GetFullPath(siteDirFull);
if (!normalizedPath.StartsWith(normalizedSiteDir + Path.DirectorySeparatorChar) &&
!normalizedPath.Equals(normalizedSiteDir))
{

View File

@@ -15,6 +15,6 @@
"PublicBasePath": "/zone"
},
"Sites": {
"BasePath": "/SiteData"
"BasePath": "SiteData"
}
}

View File

@@ -1,4 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAccessToken_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb370f448e9f5fca62da785172d83a214319335e27ac4d51840349c6dce15d68_003FAccessToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAesGcm_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3d932a3ff98244208ca84309a75a7734243600_003F2c_003F1063867b_003FAesGcm_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAny_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F331aca3f6f414013b09964063341351379060_003F67_003F87f868e3_003FAny_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@@ -117,6 +117,7 @@
<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_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>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APath_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fd3_003F7b05b2bd_003FPath_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>