summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2021-03-18 12:33:40 +0100
committerMaximilian Bosch <maximilian@mbosch.me>2021-03-20 20:43:21 +0100
commitde98a184f52837288a748778d40f93554e3e5c03 (patch)
tree5ce55f375c3309f0a109e9a9bd359b81ba9f5ac3
parent800a3dd90970a277e3f6853633bd7faf04d6691e (diff)
downloadnixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar.gz
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar.bz2
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar.lz
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar.xz
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.tar.zst
nixpkgs-de98a184f52837288a748778d40f93554e3e5c03.zip
wiki-js: init at 2.5.191
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/web-apps/wiki-js.nix139
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/wiki-js.nix152
-rw-r--r--pkgs/servers/web-apps/wiki-js/default.nix25
-rw-r--r--pkgs/top-level/all-packages.nix2
6 files changed, 320 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 7a84e2620f8..3018ecd2845 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -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
diff --git a/nixos/modules/services/web-apps/wiki-js.nix b/nixos/modules/services/web-apps/wiki-js.nix
new file mode 100644
index 00000000000..1a6259dffee
--- /dev/null
+++ b/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 ];
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 251f24a9a08..e0b789e9ece 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -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 {};
diff --git a/nixos/tests/wiki-js.nix b/nixos/tests/wiki-js.nix
new file mode 100644
index 00000000000..9aa87d15366
--- /dev/null
+++ b/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()
+  '';
+})
diff --git a/pkgs/servers/web-apps/wiki-js/default.nix b/pkgs/servers/web-apps/wiki-js/default.nix
new file mode 100644
index 00000000000..7e1117e660f
--- /dev/null
+++ b/pkgs/servers/web-apps/wiki-js/default.nix
@@ -0,0 +1,25 @@
+{ stdenv, fetchurl, lib, nixosTests }:
+
+stdenv.mkDerivation rec {
+  pname = "wiki-js";
+  version = "2.5.191";
+
+  src = fetchurl {
+    url = "https://github.com/Requarks/wiki/releases/download/${version}/${pname}.tar.gz";
+    sha256 = "sha256-lEHelZTFZxcds7t3TCMcd9b3rKdml54A0/V7gcQIyPA=";
+  };
+
+  buildCommand = ''
+    mkdir $out
+    tar xzvf $src -C $out
+  '';
+
+  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 ];
+  };
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 867cd4c75dd..2164ed755d7 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -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;