diff options
author | Jonas Heinrich <onny@project-insanity.org> | 2022-01-20 14:45:35 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-20 22:45:35 +0900 |
commit | 80475b46f52a1e28a70b1866c2a8edb071208ac8 (patch) | |
tree | c5e84003dcaf37cd1e23055861dadb8ca0ba19e0 /nixos/modules | |
parent | 98ae5a9298d8a8372b626f72b34388e7848b437a (diff) |
nixos/invoiceplane: init module and package at 1.5.11 (#146909)
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/invoiceplane.nix | 305 |
2 files changed, 306 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fdf93f2e17c5d..4b2cb803e20e9 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1022,6 +1022,7 @@ ./services/web-apps/keycloak.nix ./services/web-apps/lemmy.nix ./services/web-apps/invidious.nix + ./services/web-apps/invoiceplane.nix ./services/web-apps/limesurvey.nix ./services/web-apps/mastodon.nix ./services/web-apps/mattermost.nix diff --git a/nixos/modules/services/web-apps/invoiceplane.nix b/nixos/modules/services/web-apps/invoiceplane.nix new file mode 100644 index 0000000000000..095eec36dec38 --- /dev/null +++ b/nixos/modules/services/web-apps/invoiceplane.nix @@ -0,0 +1,305 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.invoiceplane; + eachSite = cfg.sites; + user = "invoiceplane"; + webserver = config.services.${cfg.webserver}; + + invoiceplane-config = hostName: cfg: pkgs.writeText "ipconfig.php" '' + IP_URL=http://${hostName} + ENABLE_DEBUG=false + DISABLE_SETUP=false + REMOVE_INDEXPHP=false + 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_DATABASE=${cfg.database.name} + DB_PORT=${toString cfg.database.port} + SESS_EXPIRATION=864000 + ENABLE_INVOICE_DELETION=false + DISABLE_READ_ONLY=false + ENCRYPTION_KEY= + ENCRYPTION_CIPHER=AES-256 + SETUP_COMPLETED=false + ''; + + extraConfig = hostName: cfg: pkgs.writeText "extraConfig.php" '' + ${toString cfg.extraConfig} + ''; + + pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec { + pname = "invoiceplane-${hostName}"; + version = src.version; + src = pkgs.invoiceplane; + + patchPhase = '' + # Patch index.php file to load additional config file + substituteInPlace index.php \ + --replace "require('vendor/autoload.php');" "require('vendor/autoload.php'); \$dotenv = new \Dotenv\Dotenv(__DIR__, 'extraConfig.php'); \$dotenv->load();"; + ''; + + installPhase = '' + mkdir -p $out + cp -r * $out/ + + # symlink uploads and log directories + rm -r $out/uploads $out/application/logs $out/vendor/mpdf/mpdf/tmp + ln -sf ${cfg.stateDir}/uploads $out/ + ln -sf ${cfg.stateDir}/logs $out/application/ + ln -sf ${cfg.stateDir}/tmp $out/vendor/mpdf/mpdf/ + + # symlink the InvoicePlane config + ln -s ${cfg.stateDir}/ipconfig.php $out/ipconfig.php + + # symlink the extraConfig file + ln -s ${extraConfig hostName cfg} $out/extraConfig.php + + # symlink additional templates + ${concatMapStringsSep "\n" (template: "cp -r ${template}/. $out/application/views/invoice_templates/pdf/") cfg.invoiceTemplates} + ''; + }; + + siteOpts = { lib, name, ... }: + { + options = { + + enable = mkEnableOption "InvoicePlane web application"; + + stateDir = mkOption { + type = types.path; + default = "/var/lib/invoiceplane/${name}"; + description = '' + This directory is used for uploads of attachements and cache. + The directory passed here is automatically created and permissions + adjusted as required. + ''; + }; + + database = { + host = mkOption { + type = types.str; + default = "localhost"; + description = "Database host address."; + }; + + port = mkOption { + type = types.port; + default = 3306; + description = "Database host port."; + }; + + name = mkOption { + type = types.str; + default = "invoiceplane"; + description = "Database name."; + }; + + user = mkOption { + type = types.str; + default = "invoiceplane"; + description = "Database user."; + }; + + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/invoiceplane-dbpassword"; + description = '' + A file containing the password corresponding to + <option>database.user</option>. + ''; + }; + + createLocally = mkOption { + type = types.bool; + default = true; + description = "Create the database and database user locally."; + }; + }; + + invoiceTemplates = mkOption { + type = types.listOf types.path; + default = []; + description = '' + List of path(s) to respective template(s) which are copied from the 'invoice_templates/pdf' directory. + <note><para>These templates need to be packaged before use, see example.</para></note> + ''; + example = literalExpression '' + let + # Let's package an example template + template-vtdirektmarketing = pkgs.stdenv.mkDerivation { + name = "vtdirektmarketing"; + # Download the template from a public repository + src = pkgs.fetchgit { + url = "https://git.project-insanity.org/onny/invoiceplane-vtdirektmarketing.git"; + sha256 = "1hh0q7wzsh8v8x03i82p6qrgbxr4v5fb05xylyrpp975l8axyg2z"; + }; + sourceRoot = "."; + # Installing simply means copying template php file to the output directory + installPhase = "" + mkdir -p $out + cp invoiceplane-vtdirektmarketing/vtdirektmarketing.php $out/ + ""; + }; + # And then pass this package to the template list like this: + in [ template-vtdirektmarketing ] + ''; + }; + + poolConfig = mkOption { + type = with types; attrsOf (oneOf [ str int bool ]); + default = { + "pm" = "dynamic"; + "pm.max_children" = 32; + "pm.start_servers" = 2; + "pm.min_spare_servers" = 2; + "pm.max_spare_servers" = 4; + "pm.max_requests" = 500; + }; + description = '' + Options for the InvoicePlane PHP pool. See the documentation on <literal>php-fpm.conf</literal> + 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 = '' + InvoicePlane configuration. Refer to + <link xlink:href="https://github.com/InvoicePlane/InvoicePlane/blob/master/ipconfig.php.example"/> + for details on supported values. + ''; + }; + + }; + + }; +in +{ + # interface + options = { + services.invoiceplane = mkOption { + type = types.submodule { + + options.sites = mkOption { + type = types.attrsOf (types.submodule siteOpts); + default = {}; + description = "Specification of one or more WordPress sites to serve"; + }; + + options.webserver = mkOption { + type = types.enum [ "caddy" ]; + default = "caddy"; + description = '' + Which webserver to use for virtual host management. Currently only + caddy is supported. + ''; + }; + }; + default = {}; + description = "InvoicePlane configuration."; + }; + + }; + + # implementation + config = mkIf (eachSite != {}) (mkMerge [{ + + 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; + message = ''services.invoiceplane.sites."${hostName}".database.passwordFile cannot be specified if services.invoiceplane.sites."${hostName}".database.createLocally is set to true.''; + }] + ) eachSite); + + services.mysql = mkIf (any (v: v.database.createLocally) (attrValues eachSite)) { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = mapAttrsToList (hostName: cfg: cfg.database.name) eachSite; + ensureUsers = mapAttrsToList (hostName: cfg: + { name = cfg.database.user; + ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; }; + } + ) eachSite; + }; + + services.phpfpm = { + phpPackage = pkgs.php74; + pools = mapAttrs' (hostName: cfg: ( + nameValuePair "invoiceplane-${hostName}" { + inherit user; + group = webserver.group; + settings = { + "listen.owner" = webserver.user; + "listen.group" = webserver.group; + } // cfg.poolConfig; + } + )) eachSite; + }; + + } + + { + systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [ + "d ${cfg.stateDir} 0750 ${user} ${webserver.group} - -" + "f ${cfg.stateDir}/ipconfig.php 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/logs 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/uploads 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/uploads/archive 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/uploads/customer_files 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/uploads/temp 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/uploads/temp/mpdf 0750 ${user} ${webserver.group} - -" + "d ${cfg.stateDir}/tmp 0750 ${user} ${webserver.group} - -" + ]) eachSite); + + systemd.services.invoiceplane-config = { + serviceConfig.Type = "oneshot"; + script = concatStrings (mapAttrsToList (hostName: cfg: + '' + mkdir -p ${cfg.stateDir}/logs \ + ${cfg.stateDir}/uploads + if ! grep -q IP_URL "${cfg.stateDir}/ipconfig.php"; then + cp "${invoiceplane-config hostName cfg}" "${cfg.stateDir}/ipconfig.php" + fi + '') eachSite); + wantedBy = [ "multi-user.target" ]; + }; + + users.users.${user} = { + group = webserver.group; + isSystemUser = true; + }; + } + + (mkIf (cfg.webserver == "caddy") { + services.caddy = { + enable = true; + virtualHosts = mapAttrs' (hostName: cfg: ( + nameValuePair "http://${hostName}" { + extraConfig = '' + root * ${pkg hostName cfg} + file_server + + php_fastcgi unix/${config.services.phpfpm.pools."invoiceplane-${hostName}".socket} + ''; + } + )) eachSite; + }; + }) + + + ]); +} + |