diff --git a/.dockerignore b/.dockerignore index f90ce74..d755b6c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,4 +20,5 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md \ No newline at end of file +README.md +static-pages/* diff --git a/Foxnouns.Backend/Controllers/MetaController.cs b/Foxnouns.Backend/Controllers/MetaController.cs index 8552164..e22fbc1 100644 --- a/Foxnouns.Backend/Controllers/MetaController.cs +++ b/Foxnouns.Backend/Controllers/MetaController.cs @@ -12,6 +12,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using System.Text.RegularExpressions; using Foxnouns.Backend.Dto; using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Mvc; @@ -19,7 +20,7 @@ using Microsoft.AspNetCore.Mvc; namespace Foxnouns.Backend.Controllers; [Route("/api/v2/meta")] -public class MetaController : ApiControllerBase +public partial class MetaController : ApiControllerBase { private const string Repository = "https://codeberg.org/pronounscc/pronouns.cc"; @@ -48,7 +49,23 @@ public class MetaController : ApiControllerBase ) ); + [HttpGet("page/{page}")] + public async Task GetStaticPageAsync(string page, CancellationToken ct = default) + { + if (!PageRegex().IsMatch(page)) + { + throw new ApiError.BadRequest("Invalid page name"); + } + + string path = Path.Join(Directory.GetCurrentDirectory(), "static-pages", $"{page}.md"); + string text = await System.IO.File.ReadAllTextAsync(path, ct); + return Ok(text); + } + [HttpGet("/api/v2/coffee")] public IActionResult BrewCoffee() => Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot); + + [GeneratedRegex(@"^[a-z\-_]+$")] + private static partial Regex PageRegex(); } diff --git a/Foxnouns.Backend/static-pages/.gitignore b/Foxnouns.Backend/static-pages/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/Foxnouns.Backend/static-pages/.gitignore @@ -0,0 +1 @@ +* diff --git a/Foxnouns.Frontend/src/lib/markdown.ts b/Foxnouns.Frontend/src/lib/markdown.ts index 94a1a05..9c4ff35 100644 --- a/Foxnouns.Frontend/src/lib/markdown.ts +++ b/Foxnouns.Frontend/src/lib/markdown.ts @@ -7,11 +7,7 @@ const md = new MarkdownIt({ linkify: true, }).disable(["heading", "lheading", "link", "table", "blockquote"]); -const unsafeMd = new MarkdownIt({ - html: false, - breaks: true, - linkify: true, -}); +const unsafeMd = new MarkdownIt(); export const renderMarkdown = (src: string | null) => (src ? sanitize(md.render(src)) : null); diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts b/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts new file mode 100644 index 0000000..1d9e8fc --- /dev/null +++ b/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts @@ -0,0 +1,14 @@ +import { baseRequest } from "$api"; +import ApiError from "$api/error"; + +export const load = async ({ fetch, params }) => { + const resp = await baseRequest("GET", `/meta/page/${params.page}`, { fetch }); + if (resp.status < 200 || resp.status > 299) { + const err = await resp.json(); + if ("code" in err) throw new ApiError(err); + else throw new ApiError(); + } + + const pageText = await resp.text(); + return { page: params.page, text: pageText }; +}; diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte b/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte new file mode 100644 index 0000000..a156d0a --- /dev/null +++ b/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte @@ -0,0 +1,22 @@ + + + + {title} • pronouns.cc + + +
+ {@html md} +