Skip to content

Commit

Permalink
Merge pull request NixOS#281236 from melvyn2/update-kavita
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperSandro2000 authored Mar 27, 2024
2 parents da524b7 + 6bf7438 commit f87c956
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 218 deletions.
4 changes: 4 additions & 0 deletions nixos/doc/manual/release-notes/rl-2405.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,10 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m

- `nextcloud-setup.service` no longer changes the group of each file & directory inside `/var/lib/nextcloud/{config,data,store-apps}` if one of these directories has the wrong owner group. This was part of transitioning the group used for `/var/lib/nextcloud`, but isn't necessary anymore.

- `services.kavita` now uses the freeform option `services.kavita.settings` for the application settings file.
The options `services.kavita.ipAdresses` and `services.kavita.port` now exist at `services.kavita.settings.IpAddresses`
and `services.kavita.settings.IpAddresses`.

- The `krb5` module has been rewritten and moved to `security.krb5`, moving all options but `security.krb5.enable` and `security.krb5.package` into `security.krb5.settings`.

- Gitea 1.21 upgrade has several breaking changes, including:
Expand Down
63 changes: 43 additions & 20 deletions nixos/modules/services/web-apps/kavita.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@

let
cfg = config.services.kavita;
in {
settingsFormat = pkgs.formats.json { };
appsettings = settingsFormat.generate "appsettings.json" ({ TokenKey = "@TOKEN@"; } // cfg.settings);
in
{
imports = [
(lib.mkChangedOptionModule [ "services" "kavita" "ipAdresses" ] [ "services" "kavita" "settings" "IpAddresses" ] (config:
let value = lib.getAttrFromPath [ "services" "kavita" "ipAdresses" ] config; in
lib.concatStringsSep "," value
))
(lib.mkRenamedOptionModule [ "services" "kavita" "port" ] [ "services" "kavita" "settings" "Port" ])
];

options.services.kavita = {
enable = lib.mkEnableOption (lib.mdDoc "Kavita reading server");

Expand All @@ -27,16 +38,31 @@ in {
It can be generated with `head -c 32 /dev/urandom | base64`.
'';
};
port = lib.mkOption {
default = 5000;
type = lib.types.port;
description = lib.mdDoc "Port to bind to.";
};
ipAdresses = lib.mkOption {
default = ["0.0.0.0" "::"];
type = lib.types.listOf lib.types.str;
description = lib.mdDoc "IP Addresses to bind to. The default is to bind
to all IPv4 and IPv6 addresses.";

settings = lib.mkOption {
default = { };
description = lib.mdDoc ''
Kavita configuration options, as configured in {file}`appsettings.json`.
'';
type = lib.types.submodule {
freeformType = settingsFormat.type;

options = {
Port = lib.mkOption {
default = 5000;
type = lib.types.port;
description = lib.mdDoc "Port to bind to.";
};

IpAddresses = lib.mkOption {
default = "0.0.0.0,::";
type = lib.types.commas;
description = lib.mdDoc ''
IP Addresses to bind to. The default is to bind to all IPv4 and IPv6 addresses.
'';
};
};
};
};
};

Expand All @@ -46,18 +72,15 @@ in {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart = ''
umask u=rwx,g=rx,o=
cat > "${cfg.dataDir}/config/appsettings.json" <<EOF
{
"TokenKey": "$(cat ${cfg.tokenKeyFile})",
"Port": ${toString cfg.port},
"IpAddresses": "${lib.concatStringsSep "," cfg.ipAdresses}"
}
EOF
install -m600 ${appsettings} ${lib.escapeShellArg cfg.dataDir}/config/appsettings.json
${pkgs.replace-secret}/bin/replace-secret '@TOKEN@' \
''${CREDENTIALS_DIRECTORY}/token \
'${cfg.dataDir}/config/appsettings.json'
'';
serviceConfig = {
WorkingDirectory = cfg.dataDir;
ExecStart = "${lib.getExe cfg.package}";
LoadCredential = [ "token:${cfg.tokenKeyFile}" ];
ExecStart = lib.getExe cfg.package;
Restart = "always";
User = cfg.user;
};
Expand Down
46 changes: 26 additions & 20 deletions nixos/tests/kavita.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ...} : {
import ./make-test-python.nix ({ pkgs, ... }: {
name = "kavita";
meta = with pkgs.lib.maintainers; {
maintainers = [ misterio77 ];
Expand All @@ -8,29 +8,35 @@ import ./make-test-python.nix ({ pkgs, ...} : {
kavita = { config, pkgs, ... }: {
services.kavita = {
enable = true;
port = 5000;
tokenKeyFile = builtins.toFile "kavita.key" "QfpjFvjT83BLtZ74GE3U3Q==";
tokenKeyFile = builtins.toFile "kavita.key" "d26ba694b455271a8872415830fb7b5c58f8da98f9ef7f58b2ca4c34bd406512";
};
};
};

testScript = let
regUrl = "http://kavita:5000/api/Account/register";
payload = builtins.toFile "payload.json" (builtins.toJSON {
username = "foo";
password = "correcthorsebatterystaple";
email = "foo@bar";
});
in ''
kavita.start
kavita.wait_for_unit("kavita.service")
testScript =
let
regUrl = "http://kavita:5000/api/Account/register";
loginUrl = "http://kavita:5000/api/Account/login";
localeUrl = "http://kavita:5000/api/locale";
in
''
import json
# Check that static assets are working
kavita.wait_until_succeeds("curl http://kavita:5000/site.webmanifest | grep Kavita")
kavita.start
kavita.wait_for_unit("kavita.service")
# Check that registration is working
kavita.succeed("curl -fX POST ${regUrl} --json @${payload}")
# But only for the first one
kavita.fail("curl -fX POST ${regUrl} --json @${payload}")
'';
# Check that static assets are working
kavita.wait_until_succeeds("curl http://kavita:5000/site.webmanifest | grep Kavita")
# Check that registration is working
kavita.succeed("""curl -fX POST ${regUrl} --json '{"username": "foo", "password": "correcthorsebatterystaple"}'""")
# But only for the first one
kavita.fail("""curl -fX POST ${regUrl} --json '{"username": "foo", "password": "correcthorsebatterystaple"}'""")
# Log in and retrieve token
session = json.loads(kavita.succeed("""curl -fX POST ${loginUrl} --json '{"username": "foo", "password": "correcthorsebatterystaple"}'"""))
# Check list of locales
locales = json.loads(kavita.succeed(f"curl -fX GET ${localeUrl} -H 'Authorization: Bearer {session['token']}'"))
assert len(locales) > 0, "expected a list of locales"
'';
})
68 changes: 54 additions & 14 deletions pkgs/servers/web-apps/kavita/change-webroot.diff
Original file line number Diff line number Diff line change
@@ -1,39 +1,79 @@
diff --git a/API/Controllers/FallbackController.cs b/API/Controllers/FallbackController.cs
index 2f5d7fce..faaf128a 100644
index 0c925476..c7b30f39 100644
--- a/API/Controllers/FallbackController.cs
+++ b/API/Controllers/FallbackController.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.IO;
using API.Services;
using Microsoft.AspNetCore.Authorization;
@@ -22,7 +22,7 @@ public class FallbackController : Controller

public ActionResult Index()
public PhysicalFileResult Index()
{
- return PhysicalFile(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"), "text/HTML");
+ return PhysicalFile(Path.Combine("@web_root@", "index.html"), "text/HTML");
+ return PhysicalFile(Path.Combine("@webroot@", "index.html"), "text/HTML");
}
}

diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs
index 15afddf9..aff1f230 100644
--- a/API/Services/DirectoryService.cs
+++ b/API/Services/DirectoryService.cs
@@ -113,7 +113,7 @@ public class DirectoryService : IDirectoryService
ExistOrCreate(SiteThemeDirectory);
FaviconDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "config", "favicons");
ExistOrCreate(FaviconDirectory);
- LocalizationDirectory = FileSystem.Path.Join(FileSystem.Directory.GetCurrentDirectory(), "I18N");
+ LocalizationDirectory = FileSystem.Path.Join("@out@/lib/kavita-backend", "I18N");
}

/// <summary>
diff --git a/API/Services/LocalizationService.cs b/API/Services/LocalizationService.cs
index ab3ad3d8..ac813a69 100644
--- a/API/Services/LocalizationService.cs
+++ b/API/Services/LocalizationService.cs
@@ -52,8 +52,7 @@ public class LocalizationService : ILocalizationService
else
{
_localizationDirectoryUi = directoryService.FileSystem.Path.Join(
- directoryService.FileSystem.Directory.GetCurrentDirectory(),
- "wwwroot", "assets/langs");
+ "@webroot@", "assets/langs");
}

_cacheOptions = new MemoryCacheEntryOptions()
diff --git a/API/Startup.cs b/API/Startup.cs
index f84ef638..7eaeb05e 100644
index 939bfb58..1adb9373 100644
--- a/API/Startup.cs
+++ b/API/Startup.cs
@@ -33,6 +33,7 @@ using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.AspNetCore.StaticFiles;
@@ -36,6 +36,7 @@ using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -298,6 +299,7 @@ public class Startup
@@ -298,9 +299,6 @@ public class Startup
app.UsePathBase(basePath);
if (!env.IsDevelopment())
{
- // We don't update the index.html in local as we don't serve from there
- UpdateBaseUrlInIndex(basePath);
-
// Update DB with what's in config
var dataContext = serviceProvider.GetRequiredService<DataContext>();
var setting = dataContext.ServerSetting.SingleOrDefault(x => x.Key == ServerSettingKey.BaseUrl);
@@ -333,6 +334,7 @@ public class Startup

app.UseStaticFiles(new StaticFileOptions
{
+ FileProvider = new PhysicalFileProvider("@web_root@"),
+ FileProvider = new PhysicalFileProvider("@webroot@"),
ContentTypeProvider = new FileExtensionContentTypeProvider(),
HttpsCompression = HttpsCompressionMode.Compress,
OnPrepareResponse = ctx =>
@@ -394,7 +396,7 @@ public class Startup
try
{
var htmlDoc = new HtmlDocument();
- var indexHtmlPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html");
+ var indexHtmlPath = Path.Combine("@webroot@", "index.html");
htmlDoc.Load(indexHtmlPath);

var baseNode = htmlDoc.DocumentNode.SelectSingleNode("/html/head/base");
28 changes: 17 additions & 11 deletions pkgs/servers/web-apps/kavita/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

stdenvNoCC.mkDerivation (finalAttrs: {
pname = "kavita";
version = "0.7.1.4";
version = "0.7.13";

src = fetchFromGitHub {
owner = "kareadita";
repo = "kavita";
rev = "v${finalAttrs.version}";
hash = "sha256-jNhiwyz6iVSLlvMNjI689TwQYuEvTJ+QaPvvDQ4UOwc=";
hash = "sha256-S4lJTLxNjGmgBJt89i3whBglMU2EQ0VelLG6iP6bY8g=";
};

backend = buildDotnetModule {
Expand All @@ -25,18 +25,21 @@ stdenvNoCC.mkDerivation (finalAttrs: {

patches = [
# The webroot is hardcoded as ./wwwroot
(substituteAll {
src = ./change-webroot.diff;
web_root = "${finalAttrs.frontend}/lib/node_modules/kavita-webui/dist";
})
./change-webroot.diff
];
postPatch = ''
substituteInPlace API/Services/DirectoryService.cs --subst-var out
substituteInPlace API/Startup.cs API/Services/LocalizationService.cs API/Controllers/FallbackController.cs \
--subst-var-by webroot "${finalAttrs.frontend}/lib/node_modules/kavita-webui/dist/browser"
'';

executables = [ "API" ];

projectFile = "API/API.csproj";
nugetDeps = ./nuget-deps.nix;
dotnet-sdk = dotnetCorePackages.sdk_6_0;
dotnet-runtime = dotnetCorePackages.aspnetcore_6_0;
dotnet-sdk = dotnetCorePackages.sdk_8_0;
dotnet-runtime = dotnetCorePackages.aspnetcore_8_0;
};

frontend = buildNpmPackage {
Expand All @@ -48,7 +51,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
npmBuildScript = "prod";
npmFlags = [ "--legacy-peer-deps" ];
npmRebuildFlags = [ "--ignore-scripts" ]; # Prevent playwright from trying to install browsers
npmDepsHash = "sha256-w0CuTPyCQyAxULvqd6+GiZaPlO8fh4xLmbEnGA47pL8=";
npmDepsHash = "sha256-jseoczC2Ay3D1wDUZbWXTYQJGSWdgobJ3+Z1bp+PQG4=";
};

dontBuild = true;
Expand All @@ -64,15 +67,18 @@ stdenvNoCC.mkDerivation (finalAttrs: {
runHook postInstall
'';

passthru.tests = { inherit (nixosTests) kavita; };
passthru = {
tests = { inherit (nixosTests) kavita; };
updateScript = ./update.sh;
};

meta = {
description = "A fast, feature rich, cross platform reading server";
homepage = "https://kavitareader.com";
changelog = "https://github.com/kareadita/kavita/releases/tag/${finalAttrs.src.rev}";
license = lib.licenses.gpl3Only;
platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ misterio77 ];
maintainers = with lib.maintainers; [ misterio77 nevivurn ];
mainProgram = "kavita";
};
})
Loading

0 comments on commit f87c956

Please sign in to comment.