Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ The format is based on [Keep a Changelog v1.1.0][keep-a-changelog]. See [the REA
This file only documents changes in the site engine, not any changes in the
content or the hosting infrastructure.

## [Unreleased]
### Changed
- Minor text updates.

## [5.0.0] - 2025-03-27
### Removed
- **Breaking change:** removed the EvilPlanner functionality, including everything (server API, pages, resources) related to daily quotes.
Expand Down
7 changes: 7 additions & 0 deletions ForneverMind.Core/ForneverMind.Core.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<Compile Include="LanguageLinks.fs" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions ForneverMind.Core/LanguageLinks.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ForneverMind.Core

type LanguageLink = {
IsActive: bool
Link: string
}

type LanguageLinks = {
English: LanguageLink
Russian: LanguageLink
}
18 changes: 18 additions & 0 deletions ForneverMind.Razor/BasePageModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using ForneverMind.Core;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace ForneverMind.Razor;

public class BasePageModel : PageModel
{
public LanguageLinks Links => new(
english: new LanguageLink(isActive: false, link: ProduceLink(PageContext, "en")),
russian: new LanguageLink(isActive: false, link: ProduceLink(PageContext, "ru"))
);

private static string ProduceLink(PageContext context, string newLanguage)
{
var currentUrl = context.HttpContext.Request.Path.Value;
return $"{newLanguage}/{currentUrl?.Substring("/en".Length)}";
}
}
17 changes: 17 additions & 0 deletions ForneverMind.Razor/ForneverMind.Razor.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ForneverMind.Core\ForneverMind.Core.fsproj" />
</ItemGroup>

</Project>
65 changes: 65 additions & 0 deletions ForneverMind.Razor/Pages/Shared/en/_Layout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!--
SPDX-FileCopyrightText: 2025 Friedrich von Never <[email protected]>

SPDX-License-Identifier: MIT
-->

@model ForneverMind.Razor.BasePageModel

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>F. von Never — @ViewBag.Title</title>
<base href="/en/"/>
<link rel="alternate" type="application/rss+xml" href="./rss.xml" title="RSS Feed"/>
<link rel="stylesheet" type="text/css" href="../app/app.css"/>
</head>
<body>

<div id="header">
<div id="logo">
<a href="./">Engineer, Programmer, Gentleman</a>
</div>
<div id="navigation">
<a href="./archive.html">Posts</a>
<a href="./talks.html">Talks</a>
<a href="./contact.html">Contacts</a>
</div>
</div>

<div id="content">
<div class="header-group">
<h1 class="header">@ViewBag.Title</h1>
@if (Model.Links.English.IsActive)
{
<div class="languages">
@if (Model.Links.Russian.IsActive)
{
<a href="@Model.Links.Russian.Link" class="tag">Rus</a>
}
</div>
}
</div>

@RenderBody()
</div>
<footer>
<div>
RSS:
<a class="tag" href="./rss.xml">Eng</a>
<a class="tag" href="/rss.xml">Eng+Rus</a>
</div>
<div>
<!-- REUSE-IgnoreStart -->
© fornever.me contributors 2025
<!-- REUSE-IgnoreEnd -->
</div>
<div>
<a class="tag" href="https://github.com/ForNeVeR/fornever.me">GitHub</a>
</div>
</footer>
@RenderSection("scripts", false)

</body>
</html>
65 changes: 65 additions & 0 deletions ForneverMind.Razor/Pages/Shared/ru/_Layout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!--
SPDX-FileCopyrightText: 2025 Friedrich von Never <[email protected]>

SPDX-License-Identifier: MIT
-->

@model ForneverMind.Razor.BasePageModel

<!DOCTYPE html>
<html lang="ru">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>F. von Never — @ViewBag.Title</title>
<base href="/ru/"/>
<link rel="alternate" type="application/rss+xml" href="./rss.xml" title="RSS Feed"/>
<link rel="stylesheet" type="text/css" href="../app/app.css"/>
</head>
<body>

<div id="header">
<div id="logo">
<a href="./">Инженер, программист, джентльмен</a>
</div>
<div id="navigation">
<a href="./archive.html">Посты</a>
<a href="./talks.html">Доклады</a>
<a href="./contact.html">Контакты</a>
</div>
</div>

<div id="content">
<div class="header-group">
<h1 class="header">@ViewBag.Title</h1>
@if (Model.Links.Russian.IsActive)
{
<div class="languages">
@if (Model.Links.English.IsActive)
{
<a href="@Model.Links.English.Link" class="tag">Eng</a>
}
</div>
}
</div>

@RenderBody()
</div>
<footer>
<div>
RSS:
<a class="tag" href="./rss.xml">Rus</a>
<a class="tag" href="/rss.xml">Rus+Eng</a>
</div>
<div>
<!-- REUSE-IgnoreStart -->
© fornever.me contributors 2025
<!-- REUSE-IgnoreEnd -->
</div>
<div>
<a class="tag" href="https://github.com/ForNeVeR/fornever.me">GitHub</a>
</div>
</footer>
@RenderSection("scripts", false)

</body>
</html>
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
@page
@model ForneverMind.Razor.BasePageModel

<!--
SPDX-FileCopyrightText: 2025 Friedrich von Never <[email protected]>

SPDX-License-Identifier: MIT
-->

@{
Layout = "en/_Layout.cshtml";
ViewBag.Title = "Page Not Found";
Model.Response.StatusCode = 404;
}

<p>The requested page does not exist.</p>
3 changes: 3 additions & 0 deletions ForneverMind.Razor/Pages/en/_ViewStart.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
Layout = "en/_Layout";
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
@page
@model ForneverMind.Razor.BasePageModel

<!--
SPDX-FileCopyrightText: 2025 Friedrich von Never <[email protected]>

SPDX-License-Identifier: MIT
-->

@{
Layout = "ru/_Layout.cshtml";
ViewBag.Title = "Страница не найдена";
Model.Response.StatusCode = 404;
}

<p>Страница по этому адресу не существует.</p>
<p>Страницы по этому адресу не существует.</p>
3 changes: 3 additions & 0 deletions ForneverMind.Razor/Pages/ru/_ViewStart.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
Layout = "ru/_Layout";
}
20 changes: 20 additions & 0 deletions ForneverMind.Tests/RouteTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[<Xunit.Collection(ForneverMind.TestFramework.IntegrationTestUtil.IntegrationTests)>]
module ForneverMind.Tests.RouteTests

open System.Net
open System.Threading.Tasks

open Xunit
Expand All @@ -14,5 +15,24 @@ open ForneverMind.TestFramework.IntegrationTestUtil
[<Fact>]
let ``Index page should resolve correctly``(): Task = withWebApp(fun client -> task {
let! result = client.GetAsync "/"
Assert.Equal("/en/", result.RequestMessage.RequestUri.PathAndQuery)
Assert.Equal("text/html", result.Content.Headers.ContentType.MediaType)
})

[<Fact>]
let ``404 page should be resolved``(): Task = withWebApp(fun client -> task {
let doTest (url: string) message = task {
let! result = client.GetAsync url
let! content = result.Content.ReadAsStringAsync()

Assert.Equal(HttpStatusCode.NotFound, result.StatusCode)
Assert.Equal("text/html", result.Content.Headers.ContentType.MediaType)
Assert.Contains(message, content)
}

do! doTest "/en/404" "The requested page does not exist."
do! doTest "/ru/404" "Страницы по этому адресу не существует."
do! doTest "/en/blah-blah" "The requested page does not exist."
do! doTest "/ru/blah-blah" "Страницы по этому адресу не существует."
do! doTest "/blah-blah" "The requested page does not exist."
})
12 changes: 12 additions & 0 deletions ForneverMind.sln
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{EEF302B2-6
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ForneverMind.TestFramework", "ForneverMind.TestFramework\ForneverMind.TestFramework.fsproj", "{CC92AD22-D198-46B2-8F33-45F6B5BF1EEE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForneverMind.Razor", "ForneverMind.Razor\ForneverMind.Razor.csproj", "{41A78B9F-701F-41A2-B776-185780EBE19D}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ForneverMind.Core", "ForneverMind.Core\ForneverMind.Core.fsproj", "{AAFD0512-7132-45E1-A91A-BFCAD532EA4F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -74,6 +78,14 @@ Global
{CC92AD22-D198-46B2-8F33-45F6B5BF1EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC92AD22-D198-46B2-8F33-45F6B5BF1EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC92AD22-D198-46B2-8F33-45F6B5BF1EEE}.Release|Any CPU.Build.0 = Release|Any CPU
{41A78B9F-701F-41A2-B776-185780EBE19D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41A78B9F-701F-41A2-B776-185780EBE19D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41A78B9F-701F-41A2-B776-185780EBE19D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41A78B9F-701F-41A2-B776-185780EBE19D}.Release|Any CPU.Build.0 = Release|Any CPU
{AAFD0512-7132-45E1-A91A-BFCAD532EA4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAFD0512-7132-45E1-A91A-BFCAD532EA4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAFD0512-7132-45E1-A91A-BFCAD532EA4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAFD0512-7132-45E1-A91A-BFCAD532EA4F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
13 changes: 13 additions & 0 deletions ForneverMind/Controllers/PagesController.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace ForneverMind.Controllers

open Microsoft.AspNetCore.Mvc

open ForneverMind

[<Route("/")>]
type PagesController() =
inherit Controller()

[<Route("/")>]
member this.Get(): IActionResult =
RedirectResult $"/{Common.defaultLanguage}/"
5 changes: 3 additions & 2 deletions ForneverMind/ForneverMind.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SPDX-License-Identifier: MIT
<Compile Include="PagesModule.fs" />
<Compile Include="RssModule.fs" />
<Compile Include="RoutesModule.fs" />
<Compile Include="Controllers\PagesController.fs" />
<Compile Include="Program.fs" />
<Content Include="posts\**" CopyToPublishDirectory="Always" />
<Content Include="server.js" CopyToPublishDirectory="Always" />
Expand All @@ -50,8 +51,8 @@ SPDX-License-Identifier: MIT
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="RazorLight" Version="2.3.1" />
<PackageReference Include="WilderMinds.RssSyndication" Version="1.7.1" />
<ProjectReference Include="..\ForneverMind.Frontend\ForneverMind.Frontend.proj"
ReferenceOutputAssembly="false"/>
<ProjectReference Include="..\ForneverMind.Frontend\ForneverMind.Frontend.proj" ReferenceOutputAssembly="false"/>
<ProjectReference Include="..\ForneverMind.Razor\ForneverMind.Razor.csproj" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
Expand Down
Loading
Loading