diff options
author | Moritz 'e1mo' Fromm <git@e1mo.de> | 2023-01-06 02:36:30 +0100 |
---|---|---|
committer | Moritz 'e1mo' Fromm <git@e1mo.de> | 2023-01-06 22:02:37 +0100 |
commit | 236d90fde0b376f00e8eea32ea6af37ec3de4766 (patch) | |
tree | b24fb617272ad5e1c83720b18d06a7b1c59393ca /nixos/modules/services | |
parent | 108627107dbfb7ed1906de3760a8dc995947a28e (diff) |
nixos/dokuwiki: Overhaul for structured settings
Added the RFC42-style added the posibility to use `services.dokuwiki.sites.<name>.settings' instead of passing a plain string to `<name>.extraConfig`. ´<name>.pluginsConfig` now also accepts structured configuration.
Diffstat (limited to 'nixos/modules/services')
-rw-r--r-- | nixos/modules/services/web-apps/dokuwiki.nix | 269 |
1 files changed, 199 insertions, 70 deletions
diff --git a/nixos/modules/services/web-apps/dokuwiki.nix b/nixos/modules/services/web-apps/dokuwiki.nix index 1c40441bb55fc..d90dd8ace4125 100644 --- a/nixos/modules/services/web-apps/dokuwiki.nix +++ b/nixos/modules/services/web-apps/dokuwiki.nix @@ -15,30 +15,64 @@ let extraConfig = mkPhpIni cfg.phpOptions; }; - dokuwikiAclAuthConfig = hostName: cfg: pkgs.writeText "acl.auth-${hostName}.php" '' + dokuwikiAclAuthConfig = hostName: cfg: let + inherit (cfg) acl; + acl_gen = concatMapStringsSep "\n" (l: "${l.page} \t ${l.actor} \t ${toString l.level}"); + in pkgs.writeText "acl.auth-${hostName}.php" '' # acl.auth.php # <?php exit()?> # # Access Control Lists # - ${toString cfg.acl} + ${if isString acl then acl else acl_gen acl} ''; - dokuwikiLocalConfig = hostName: cfg: pkgs.writeText "local-${hostName}.php" '' - <?php - $conf['savedir'] = '${cfg.stateDir}'; - $conf['superuser'] = '${toString cfg.superUser}'; - $conf['useacl'] = '${toString cfg.aclUse}'; - $conf['disableactions'] = '${cfg.disableActions}'; + mergeConfig = cfg: { + useacl = false; # Dokuwiki default + savedir = cfg.stateDir; + } // cfg.settings; + + writePhpFile = name: text: pkgs.writeTextFile { + inherit name; + text = "<?php\n${text}"; + checkPhase = "${pkgs.php81}/bin/php --syntax-check $target"; + }; + + mkPhpValue = v: let + isHasAttr = s: isAttrs v && hasAttr s v; + in + if isString v then escapeShellArg v + # NOTE: If any value contains a , (comma) this will not get escaped + else if isList v && any lib.strings.isCoercibleToString v then escapeShellArg (concatMapStringsSep "," toString v) + else if isInt v then toString v + else if isBool v then toString (if v then 1 else 0) + else if isHasAttr "_file" then "trim(file_get_contents(${lib.escapeShellArg v._file}))" + else if isHasAttr "_raw" then v._raw + else abort "The dokuwiki localConf value ${lib.generators.toPretty {} v} can not be encoded." + ; + + mkPhpAttrVals = v: flatten (mapAttrsToList mkPhpKeyVal v); + mkPhpKeyVal = k: v: let + values = if (isAttrs v && (hasAttr "_file" v || hasAttr "_raw" v )) || !isAttrs v then + [" = ${mkPhpValue v};"] + else + mkPhpAttrVals v; + in map (e: "[${escapeShellArg k}]${e}") (flatten values); + + dokuwikiLocalConfig = hostName: cfg: let + conf_gen = c: map (v: "$conf${v}") (mkPhpAttrVals c); + in writePhpFile "local-${hostName}.php" '' + ${concatStringsSep "\n" (conf_gen cfg.mergedConfig)} ${toString cfg.extraConfig} ''; - dokuwikiPluginsLocalConfig = hostName: cfg: pkgs.writeText "plugins.local-${hostName}.php" '' - <?php - ${cfg.pluginsConfig} + dokuwikiPluginsLocalConfig = hostName: cfg: let + pc = cfg.pluginsConfig; + pc_gen = pc: concatStringsSep "\n" (mapAttrsToList (n: v: "$plugins['${n}'] = ${boolToString v};") pc); + in writePhpFile "plugins.local-${hostName}.php" '' + ${if isString pc then pc else pc_gen pc} ''; - pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec { pname = "dokuwiki-${hostName}"; version = src.version; @@ -49,22 +83,82 @@ let cp -r * $out/ # symlink the dokuwiki config - ln -s ${dokuwikiLocalConfig hostName cfg} $out/share/dokuwiki/local.php + ln -sf ${dokuwikiLocalConfig hostName cfg} $out/share/dokuwiki/conf/local.php # symlink plugins config - ln -s ${dokuwikiPluginsLocalConfig hostName cfg} $out/share/dokuwiki/plugins.local.php + ln -sf ${dokuwikiPluginsLocalConfig hostName cfg} $out/share/dokuwiki/conf/plugins.local.php - # symlink acl - ln -s ${dokuwikiAclAuthConfig hostName cfg} $out/share/dokuwiki/acl.auth.php + # symlink acl (if needed) + ${optionalString (cfg.mergedConfig.useacl && cfg.acl != null) "ln -sf ${dokuwikiAclAuthConfig hostName cfg} $out/share/dokuwiki/acl.auth.php"} # symlink additional plugin(s) and templates(s) - ${concatMapStringsSep "\n" (template: "ln -s ${template} $out/share/dokuwiki/lib/tpl/${template.name}") cfg.templates} - ${concatMapStringsSep "\n" (plugin: "ln -s ${plugin} $out/share/dokuwiki/lib/plugins/${plugin.name}") cfg.plugins} + ${concatMapStringsSep "\n" (template: "ln -sf ${template} $out/share/dokuwiki/lib/tpl/${template.name}") cfg.templates} + ${concatMapStringsSep "\n" (plugin: "ln -sf ${plugin} $out/share/dokuwiki/lib/plugins/${plugin.name}") cfg.plugins} ''; }; + aclOpts = { ... }: { + options = { + + page = mkOption { + type = types.str; + description = "Page or namespace to restrict"; + example = "start"; + }; + + actor = mkOption { + type = types.str; + description = "User or group to restrict"; + example = "@external"; + }; + + level = let + available = { + "none" = 0; + "read" = 1; + "edit" = 2; + "create" = 4; + "upload" = 8; + "delete" = 16; + }; + in mkOption { + type = types.enum ((attrValues available) ++ (attrNames available)); + apply = x: if isInt x then x else available.${x}; + description = '' + Permission level to restrict the actor(s) to. + See <https://www.dokuwiki.org/acl#background_info> for explanation + ''; + example = "read"; + }; + + }; + }; + siteOpts = { config, lib, name, ... }: { + imports = [ + # NOTE: These will sadly not print the absolute argument path but only the name. Related to #96006 + (mkRenamedOptionModule [ "aclUse" ] [ "settings" "useacl" ] ) + (mkRenamedOptionModule [ "superUser" ] [ "settings" "superuser" ] ) + (mkRenamedOptionModule [ "disableActions" ] [ "settings" "disableactions" ] ) + ({ config, options, name, ...}: { + config.warnings = + (optional (isString config.pluginsConfig) '' + Passing plain strings to services.dokuwiki.sites.${name}.pluginsConfig has been deprecated and will not be continue to be supported in the future. + Please pass structured settings instead. + '') + ++ (optional (isString config.acl) '' + Passing a plain string to services.dokuwiki.sites.${name}.acl has been deprecated and will not continue to be supported in the future. + Please pass structured settings instead. + '') + ++ (optional (config.extraConfig != null) '' + services.dokuwiki.sites.${name}.extraConfig is deprecated and will be removed in the future. + Please pass structured settings to services.dokuwiki.sites.${name}.settings instead. + '') + ; + }) + ]; + options = { enable = mkEnableOption (lib.mdDoc "DokuWiki web application."); @@ -82,9 +176,22 @@ let }; acl = mkOption { - type = types.nullOr types.lines; + type = with types; nullOr (oneOf [ lines (listOf (submodule aclOpts)) ]); default = null; - example = "* @ALL 8"; + example = literalExpression '' + [ + { + page = "start"; + actor = "@external"; + level = "read"; + } + { + page = "*"; + actor = "@users"; + level = "upload"; + } + ] + ''; description = lib.mdDoc '' Access Control Lists: see <https://www.dokuwiki.org/acl> Mutually exclusive with services.dokuwiki.aclFile @@ -97,7 +204,7 @@ let aclFile = mkOption { type = with types; nullOr str; - default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null; + default = if (config.mergedConfig.useacl && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null; description = lib.mdDoc '' Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl Mutually exclusive with services.dokuwiki.acl which is preferred. @@ -107,42 +214,22 @@ let example = "/var/lib/dokuwiki/${name}/acl.auth.php"; }; - aclUse = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Necessary for users to log in into the system. - Also limits anonymous users. When disabled, - everyone is able to create and edit content. - ''; - }; - pluginsConfig = mkOption { - type = types.lines; - default = '' - $plugins['authad'] = 0; - $plugins['authldap'] = 0; - $plugins['authmysql'] = 0; - $plugins['authpgsql'] = 0; - ''; + type = with types; oneOf [lines (attrsOf bool)]; + default = { + authad = false; + authldap = false; + authmysql = false; + authpgsql = false; + }; description = lib.mdDoc '' List of the dokuwiki (un)loaded plugins. ''; }; - superUser = mkOption { - type = types.nullOr types.str; - default = "@admin"; - description = lib.mdDoc '' - You can set either a username, a list of usernames (“admin1,admin2”), - or the name of a group by prepending an @ char to the groupname - Consult documentation <https://www.dokuwiki.org/config:superuser> for further instructions. - ''; - }; - usersFile = mkOption { type = with types; nullOr str; - default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null; + default = if config.mergedConfig.useacl then "/var/lib/dokuwiki/${name}/users.auth.php" else null; description = lib.mdDoc '' Location of the dokuwiki users file. List of users. Format: @@ -157,17 +244,6 @@ let example = "/var/lib/dokuwiki/${name}/users.auth.php"; }; - disableActions = mkOption { - type = types.nullOr types.str; - default = ""; - example = "search,register"; - description = lib.mdDoc '' - Disable individual action modes. Refer to - <https://www.dokuwiki.org/config:action_modes> - for details on supported values. - ''; - }; - plugins = mkOption { type = types.listOf types.path; default = []; @@ -266,7 +342,50 @@ let ''; }; + settings = mkOption { + type = types.attrsOf types.anything; + default = { + useacl = true; + superuser = "admin"; + }; + description = lib.mdDoc '' + Structural DokuWiki configuration. + Refer to <https://www.dokuwiki.org/config> + for details and supported values. + Settings can either be directly set from nix, + loaded from a file using `._file` or obtained from any + PHP function calls using `._raw`. + ''; + example = literalExpression '' + { + title = "My Wiki"; + userewrite = 1; + disableactions = [ "register" ]; # Will be concatenated with commas + plugin.smtp = { + smtp_pass._file = "/var/run/secrets/dokuwiki/smtp_pass"; + smtp_user._raw = "getenv('DOKUWIKI_SMTP_USER')"; + }; + } + ''; + }; + + mergedConfig = mkOption { + readOnly = true; + default = mergeConfig config; + defaultText = literalExpression '' + { + useacl = true; + } + ''; + description = lib.mdDoc '' + Read only representation of the final configuration. + ''; + }; + extraConfig = mkOption { + # This Option is deprecated and only kept until sometime before 23.05 for compatibility reasons + # FIXME (@e1mo): Actually remember removing this before 23.05. + visible = false; type = types.nullOr types.lines; default = null; example = '' @@ -277,15 +396,26 @@ let DokuWiki configuration. Refer to <https://www.dokuwiki.org/config> for details on supported values. + + **Note**: Please pass Structured settings via + `services.dokuwiki.sites.${name}.settings` instead. ''; }; + # Required for the mkRenamedOptionModule + # TODO: Remove me once https://github.com/NixOS/nixpkgs/issues/96006 is fixed + # or the aclUse, ... options are removed. + warnings = mkOption { + type = types.listOf types.unspecified; + default = [ ]; + visible = false; + internal = true; }; }; + }; in { - # interface options = { services.dokuwiki = { @@ -315,14 +445,16 @@ in # implementation config = mkIf (eachSite != {}) (mkMerge [{ + warnings = flatten (mapAttrsToList (_: cfg: cfg.warnings) eachSite); + assertions = flatten (mapAttrsToList (hostName: cfg: [{ - assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null); - message = "Either services.dokuwiki.sites.${hostName}.acl or services.dokuwiki.sites.${hostName}.aclFile is mandatory if aclUse true"; + assertion = cfg.mergedConfig.useacl -> (cfg.acl != null || cfg.aclFile != null); + message = "Either services.dokuwiki.sites.${hostName}.acl or services.dokuwiki.sites.${hostName}.aclFile is mandatory if settings.useacl is true"; } { - assertion = cfg.usersFile != null -> cfg.aclUse != false; - message = "services.dokuwiki.sites.${hostName}.aclUse must must be true if usersFile is not null"; + assertion = cfg.usersFile != null -> cfg.mergedConfig.useacl != false; + message = "services.dokuwiki.sites.${hostName}.settings.useacl must must be true if usersFile is not null"; } ]) eachSite); @@ -332,12 +464,9 @@ in group = webserver.group; phpPackage = mkPhpPackage cfg; - phpEnv = { - DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig hostName cfg}"; - DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig hostName cfg}"; - } // optionalAttrs (cfg.usersFile != null) { + phpEnv = optionalAttrs (cfg.usersFile != null) { DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}"; - } //optionalAttrs (cfg.aclUse) { + } // optionalAttrs (cfg.mergedConfig.useacl) { DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig hostName cfg}" else "${toString cfg.aclFile}"; }; |