Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wiki-js: init at 2.5.191 #116738

Merged
merged 3 commits into from Mar 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Expand Up @@ -921,6 +921,7 @@
./services/web-apps/selfoss.nix
./services/web-apps/shiori.nix
./services/web-apps/virtlyst.nix
./services/web-apps/wiki-js.nix
./services/web-apps/whitebophir.nix
./services/web-apps/wordpress.nix
./services/web-apps/youtrack.nix
Expand Down
139 changes: 139 additions & 0 deletions nixos/modules/services/web-apps/wiki-js.nix
@@ -0,0 +1,139 @@
{ lib, pkgs, config, ... }:

with lib;

let
cfg = config.services.wiki-js;

format = pkgs.formats.json { };

configFile = format.generate "wiki-js.yml" cfg.settings;
in {
options.services.wiki-js = {
enable = mkEnableOption "wiki-js";

environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/root/wiki-js.env";
description = ''
Environment fiel to inject e.g. secrets into the configuration.
'';
};

stateDirectoryName = mkOption {
default = "wiki-js";
type = types.str;
description = ''
Name of the directory in <filename>/var/lib</filename>.
'';
};

settings = mkOption {
default = {};
type = types.submodule {
freeformType = format.type;
options = {
port = mkOption {
type = types.port;
default = 3000;
description = ''
TCP port the process should listen to.
'';
};

bindIP = mkOption {
default = "0.0.0.0";
type = types.str;
description = ''
IPs the service should listen to.
'';
};

db = {
type = mkOption {
default = "postgres";
type = types.enum [ "postgres" "mysql" "mariadb" "mssql" ];
description = ''
Database driver to use for persistence. Please note that <literal>sqlite</literal>
is currently not supported as the build process for it is currently not implemented
in <package>pkgs.wiki-js</package> and it's not recommended by upstream for
production use.
'';
};
host = mkOption {
type = types.str;
example = "/run/postgresql";
description = ''
Hostname or socket-path to connect to.
'';
};
db = mkOption {
default = "wiki";
type = types.str;
description = ''
Name of the database to use.
'';
};
};

logLevel = mkOption {
default = "info";
type = types.enum [ "error" "warn" "info" "verbose" "debug" "silly" ];
description = ''
Define how much detail is supposed to be logged at runtime.
'';
};

offline = mkEnableOption "offline mode" // {
description = ''
Disable latest file updates and enable
<link xlink:href="https://docs.requarks.io/install/sideload">sideloading</link>.
'';
};
};
};
description = ''
Settings to configure <package>wiki-js</package>. This directly
corresponds to <link xlink:href="https://docs.requarks.io/install/config">the upstream
configuration options</link>.

Secrets can be injected via the environment by
<itemizedlist>
<listitem><para>specifying <xref linkend="opt-services.wiki-js.environmentFile" />
to contain secrets</para></listitem>
<listitem><para>and setting sensitive values to <literal>$(ENVIRONMENT_VAR)</literal>
with this value defined in the environment-file.</para></listitem>
</itemizedlist>
'';
};
};

config = mkIf cfg.enable {
services.wiki-js.settings.dataPath = "/var/lib/${cfg.stateDirectoryName}";
systemd.services.wiki-js = {
description = "A modern and powerful wiki app built on Node.js";
documentation = [ "https://docs.requarks.io/" ];
wantedBy = [ "multi-user.target" ];

path = with pkgs; [ coreutils ];
preStart = ''
ln -sf ${configFile} /var/lib/${cfg.stateDirectoryName}/config.yml
ln -sf ${pkgs.wiki-js}/server /var/lib/${cfg.stateDirectoryName}
ln -sf ${pkgs.wiki-js}/assets /var/lib/${cfg.stateDirectoryName}
ln -sf ${pkgs.wiki-js}/package.json /var/lib/${cfg.stateDirectoryName}/package.json
'';

serviceConfig = {
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
StateDirectory = cfg.stateDirectoryName;
WorkingDirectory = "/var/lib/${cfg.stateDirectoryName}";
DynamicUser = true;
PrivateTmp = true;
ExecStart = "${pkgs.nodejs}/bin/node ${pkgs.wiki-js}/server";
};
};
};

meta.maintainers = with maintainers; [ ma27 ];
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Expand Up @@ -423,6 +423,7 @@ in
virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
vscodium = handleTest ./vscodium.nix {};
wasabibackend = handleTest ./wasabibackend.nix {};
wiki-js = handleTest ./wiki-js.nix {};
wireguard = handleTest ./wireguard {};
wordpress = handleTest ./wordpress.nix {};
xandikos = handleTest ./xandikos.nix {};
Expand Down
152 changes: 152 additions & 0 deletions nixos/tests/wiki-js.nix
@@ -0,0 +1,152 @@
import ./make-test-python.nix ({ pkgs, lib, ...} : {
name = "wiki-js";
meta = with pkgs.lib.maintainers; {
maintainers = [ ma27 ];
};

machine = { pkgs, ... }: {
virtualisation.memorySize = 2048;
services.wiki-js = {
enable = true;
settings.db.host = "/run/postgresql";
settings.db.user = "wiki-js";
settings.logLevel = "debug";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "wiki" ];
ensureUsers = [
{ name = "wiki-js";
ensurePermissions."DATABASE wiki" = "ALL PRIVILEGES";
}
];
};
systemd.services.wiki-js = {
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
};
environment.systemPackages = with pkgs; [ jq ];
};

testScript = let
payloads.finalize = pkgs.writeText "finalize.json" (builtins.toJSON {
adminEmail = "webmaster@example.com";
adminPassword = "notapassword";
adminPasswordConfirm = "notapassword";
siteUrl = "http://localhost:3000";
telemetry = false;
});
payloads.login = pkgs.writeText "login.json" (builtins.toJSON [{
operationName = null;
extensions = {};
query = ''
mutation ($username: String!, $password: String!, $strategy: String!) {
authentication {
login(username: $username, password: $password, strategy: $strategy) {
responseResult {
succeeded
errorCode
slug
message
__typename
}
jwt
mustChangePwd
mustProvideTFA
mustSetupTFA
continuationToken
redirect
tfaQRImage
__typename
}
__typename
}
}
'';
variables = {
password = "notapassword";
strategy = "local";
username = "webmaster@example.com";
};
}]);
payloads.content = pkgs.writeText "content.json" (builtins.toJSON [{
extensions = {};
operationName = null;
query = ''
mutation ($content: String!, $description: String!, $editor: String!, $isPrivate: Boolean!, $isPublished: Boolean!, $locale: String!, $path: String!, $publishEndDate: Date, $publishStartDate: Date, $scriptCss: String, $scriptJs: String, $tags: [String]!, $title: String!) {
pages {
create(content: $content, description: $description, editor: $editor, isPrivate: $isPrivate, isPublished: $isPublished, locale: $locale, path: $path, publishEndDate: $publishEndDate, publishStartDate: $publishStartDate, scriptCss: $scriptCss, scriptJs: $scriptJs, tags: $tags, title: $title) {
responseResult {
succeeded
errorCode
slug
message
__typename
}
page {
id
updatedAt
__typename
}
__typename
}
__typename
}
}
'';
variables = {
content = "# Header\n\nHello world!";
description = "";
editor = "markdown";
isPrivate = false;
isPublished = true;
locale = "en";
path = "home";
publishEndDate = "";
publishStartDate = "";
scriptCss = "";
scriptJs = "";
tags = [];
title = "Hello world";
};
}]);
in ''
machine.start()
machine.wait_for_unit("multi-user.target")
machine.wait_for_open_port(3000)

machine.succeed("curl -sSf localhost:3000")

with subtest("Setup"):
result = machine.succeed(
"set -o pipefail; curl -sSf localhost:3000/finalize -X POST -d "
+ "@${payloads.finalize} -H 'Content-Type: application/json' "
+ "| jq .ok | xargs echo"
)
assert result.strip() == "true", f"Expected true, got {result}"

# During the setup the service gets restarted, so we use this
# to check if the setup is done.
machine.wait_until_fails("curl -sSf localhost:3000")
machine.wait_until_succeeds("curl -sSf localhost:3000")

with subtest("Base functionality"):
auth = machine.succeed(
"set -o pipefail; curl -sSf localhost:3000/graphql -X POST "
+ "-d @${payloads.login} -H 'Content-Type: application/json' "
+ "| jq '.[0].data.authentication.login.jwt' | xargs echo"
).strip()

assert auth

create = machine.succeed(
"set -o pipefail; curl -sSf localhost:3000/graphql -X POST "
+ "-d @${payloads.content} -H 'Content-Type: application/json' "
+ f"-H 'Authorization: Bearer {auth}' "
+ "| jq '.[0].data.pages.create.responseResult.succeeded'|xargs echo"
)
assert create.strip() == "true", f"Expected true, got {create}"

machine.shutdown()
'';
})
32 changes: 32 additions & 0 deletions pkgs/servers/web-apps/wiki-js/default.nix
@@ -0,0 +1,32 @@
{ stdenv, fetchurl, lib, nixosTests }:

stdenv.mkDerivation rec {
pname = "wiki-js";
version = "2.5.197";

src = fetchurl {
url = "https://github.com/Requarks/wiki/releases/download/${version}/${pname}.tar.gz";
sha256 = "sha256-0xM9BtQvSt5WkbKBri+KxB+Ghc4wgY8/TUgI6PCFmm0=";
};

sourceRoot = ".";

dontBuild = true;
installPhase = ''
runHook preInstall

mkdir $out
cp -r . $out

runHook postInstall
'';

passthru.tests = { inherit (nixosTests) wiki-js; };

meta = with lib; {
homepage = "https://js.wiki/";
description = "A modern and powerful wiki app built on Node.js";
license = licenses.agpl3Only;
maintainers = with maintainers; [ ma27 ];
};
}
2 changes: 2 additions & 0 deletions pkgs/top-level/all-packages.nix
Expand Up @@ -29884,6 +29884,8 @@ in
pythonPackages = python3Packages;
};

wiki-js = callPackage ../servers/web-apps/wiki-js { };

winePackagesFor = wineBuild: lib.makeExtensible (self: with self; {
callPackage = newScope self;

Expand Down