nixos/invoiceplane: merge upstream module fixes

This commit is contained in:
teutat3s 2024-06-24 22:57:44 +02:00
parent 555dd5d133
commit 2196ed1427
Signed by: teutat3s
GPG key ID: 4FA1D3FA524F22C1

View file

@ -4,9 +4,16 @@ let
inherit (lib)
any
attrValues
boolToString
concatMapStringsSep
concatStrings
concatStringsSep
escapeShellArg
flatten
isBool
isInt
isList
isString
literalExpression
mapAttrs'
mapAttrsToList
@ -16,6 +23,7 @@ let
mkMerge
mkOption
nameValuePair
optionalString
types;
cfg = config.services.invoiceplane;
@ -31,7 +39,7 @@ let
DB_HOSTNAME=${cfg.database.host}
DB_USERNAME=${cfg.database.user}
# NOTE: file_get_contents adds newline at the end of returned string
DB_PASSWORD=${if cfg.database.passwordFile == null then "" else "trim(file_get_contents('${cfg.database.passwordFile}'),\"\\r\\n\")"}
DB_PASSWORD=${optionalString (cfg.database.passwordFile != null) "trim(file_get_contents('${cfg.database.passwordFile}'), \"\\r\\n\")"}
DB_DATABASE=${cfg.database.name}
DB_PORT=${toString cfg.database.port}
SESS_EXPIRATION=864000
@ -43,19 +51,28 @@ let
REMOVE_INDEXPHP=true
'';
extraConfig = hostName: cfg: pkgs.writeText "extraConfig.php" ''
${toString cfg.extraConfig}
'';
mkPhpValue = v:
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 boolToString v
else abort "The Invoiceplane config value ${lib.generators.toPretty {} v} can not be encoded."
;
extraConfig = hostName: cfg: let
settings = mapAttrsToList (k: v: "${k}=${mkPhpValue v}") cfg.settings;
in pkgs.writeText "extraConfig.php" (concatStringsSep "\n" settings);
pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
pname = "invoiceplane-${hostName}";
version = src.version;
src = pkgs.invoiceplane;
postPhase = ''
postPatch = ''
# Patch index.php file to load additional config file
substituteInPlace index.php \
--replace "require('vendor/autoload.php');" "require('vendor/autoload.php'); \$dotenv = Dotenv\Dotenv::createImmutable(__DIR__, 'extraConfig.php'); \$dotenv->load();";
--replace-fail "require('vendor/autoload.php');" "require('vendor/autoload.php'); \$dotenv = Dotenv\Dotenv::createImmutable(__DIR__, 'extraConfig.php'); \$dotenv->load();";
'';
installPhase = ''
@ -79,16 +96,16 @@ let
'';
};
siteOpts = { lib, name, ... }:
siteOpts = { name, ... }:
{
options = {
enable = mkEnableOption (lib.mdDoc "InvoicePlane web application");
enable = mkEnableOption "InvoicePlane web application";
stateDir = mkOption {
type = types.path;
default = "/var/lib/invoiceplane/${name}";
description = lib.mdDoc ''
description = ''
This directory is used for uploads of attachments and cache.
The directory passed here is automatically created and permissions
adjusted as required.
@ -99,32 +116,32 @@ let
host = mkOption {
type = types.str;
default = "localhost";
description = lib.mdDoc "Database host address.";
description = "Database host address.";
};
port = mkOption {
type = types.port;
default = 3306;
description = lib.mdDoc "Database host port.";
description = "Database host port.";
};
name = mkOption {
type = types.str;
default = "invoiceplane";
description = lib.mdDoc "Database name.";
description = "Database name.";
};
user = mkOption {
type = types.str;
default = "invoiceplane";
description = lib.mdDoc "Database user.";
description = "Database user.";
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/invoiceplane-dbpassword";
description = lib.mdDoc ''
description = ''
A file containing the password corresponding to
{option}`database.user`.
'';
@ -133,14 +150,14 @@ let
createLocally = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc "Create the database and database user locally.";
description = "Create the database and database user locally.";
};
};
invoiceTemplates = mkOption {
type = types.listOf types.path;
default = [];
description = lib.mdDoc ''
description = ''
List of path(s) to respective template(s) which are copied from the 'invoice_templates/pdf' directory.
::: {.note}
@ -179,45 +196,44 @@ let
"pm.max_spare_servers" = 4;
"pm.max_requests" = 500;
};
description = lib.mdDoc ''
description = ''
Options for the InvoicePlane PHP pool. See the documentation on `php-fpm.conf`
for details on configuration directives.
'';
};
extraConfig = mkOption {
type = types.nullOr types.lines;
default = null;
example = ''
SETUP_COMPLETED=true
DISABLE_SETUP=true
IP_URL=https://invoice.example.com
'';
description = lib.mdDoc ''
InvoicePlane configuration. Refer to
settings = mkOption {
type = types.attrsOf types.anything;
default = {};
description = ''
Structural InvoicePlane configuration. Refer to
<https://github.com/InvoicePlane/InvoicePlane/blob/master/ipconfig.php.example>
for details on supported values.
for details and supported values.
'';
example = literalExpression ''
{
SETUP_COMPLETED = true;
DISABLE_SETUP = true;
IP_URL = "https://invoice.example.com";
}
'';
};
cron = {
enable = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
description = ''
Enable cron service which periodically runs Invoiceplane tasks.
Requires key taken from the administration page. Refer to
<https://wiki.invoiceplane.com/en/1.0/modules/recurring-invoices>
on how to configure it.
'';
};
key = mkOption {
type = types.str;
description = lib.mdDoc "Cron key taken from the administration page.";
description = "Cron key taken from the administration page.";
};
};
};
@ -237,20 +253,20 @@ in
options.sites = mkOption {
type = types.attrsOf (types.submodule siteOpts);
default = {};
description = lib.mdDoc "Specification of one or more WordPress sites to serve";
description = "Specification of one or more WordPress sites to serve";
};
options.webserver = mkOption {
type = types.enum [ "caddy" "nginx" ];
default = "caddy";
description = lib.mdDoc ''
Which webserver to use for virtual host management. Currently only
caddy is supported.
example = "nginx";
description = ''
Which webserver to use for virtual host management.
'';
};
};
default = {};
description = lib.mdDoc "InvoicePlane configuration.";
description = "InvoicePlane configuration.";
};
};
@ -258,8 +274,8 @@ in
# implementation
config = mkIf (eachSite != {}) (mkMerge [{
assertions = flatten (mapAttrsToList (hostName: cfg:
[{ assertion = cfg.database.createLocally -> cfg.database.user == user;
assertions = flatten (mapAttrsToList (hostName: cfg: [
{ assertion = cfg.database.createLocally -> cfg.database.user == user;
message = ''services.invoiceplane.sites."${hostName}".database.user must be ${user} if the database is to be automatically provisioned'';
}
{ assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
@ -377,8 +393,8 @@ in
services.nginx = {
enable = true;
virtualHosts = mapAttrs' (hostName: cfg: (
nameValuePair "${hostName}" {
root = "${pkg hostName cfg}";
nameValuePair hostName {
root = pkg hostName cfg;
extraConfig = ''
index index.php index.html index.htm;
@ -397,8 +413,8 @@ in
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:${config.services.phpfpm.pools."invoiceplane-${hostName}".socket};
include ${pkgs.nginx}/conf/fastcgi_params;
include ${pkgs.nginx}/conf/fastcgi.conf;
include ${config.services.nginx.package}/conf/fastcgi_params;
include ${config.services.nginx.package}/conf/fastcgi.conf;
'';
};
};