diff options
author | Maximilian Bosch <maximilian@mbosch.me> | 2020-02-07 23:30:40 +0100 |
---|---|---|
committer | Maximilian Bosch <maximilian@mbosch.me> | 2020-02-09 21:55:27 +0100 |
commit | 13f7b7555322f5727d4b5279102222fdbee62587 (patch) | |
tree | 7e1a3ce6ce46549e7b3f7c2cccc9fb4babdc7df2 | |
parent | 3d051f49babe518cef4a56708504efc941f56fde (diff) |
nixos/grocy: init module
Co-authored-by: elseym <elseym@me.com>
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/grocy.nix | 172 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/grocy.xml | 77 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/grocy.nix | 47 |
5 files changed, 298 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 878b77969af17..402f222f4e929 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -814,6 +814,7 @@ ./services/web-apps/dokuwiki.nix ./services/web-apps/frab.nix ./services/web-apps/gotify-server.nix + ./services/web-apps/grocy.nix ./services/web-apps/icingaweb2/icingaweb2.nix ./services/web-apps/icingaweb2/module-monitoring.nix ./services/web-apps/ihatemoney diff --git a/nixos/modules/services/web-apps/grocy.nix b/nixos/modules/services/web-apps/grocy.nix new file mode 100644 index 0000000000000..568bdfd0c4297 --- /dev/null +++ b/nixos/modules/services/web-apps/grocy.nix @@ -0,0 +1,172 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.grocy; +in { + options.services.grocy = { + enable = mkEnableOption "grocy"; + + hostName = mkOption { + type = types.str; + description = '' + FQDN for the grocy instance. + ''; + }; + + nginx.enableSSL = mkOption { + type = types.bool; + default = true; + description = '' + Whether or not to enable SSL (with ACME and let's encrypt) + for the grocy vhost. + ''; + }; + + phpfpm.settings = mkOption { + type = with types; attrsOf (oneOf [ int str bool ]); + default = { + "pm" = "dynamic"; + "php_admin_value[error_log]" = "stderr"; + "php_admin_flag[log_errors]" = true; + "listen.owner" = "nginx"; + "catch_workers_output" = true; + "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 grocy's PHPFPM pool. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/grocy"; + description = '' + Home directory of the <literal>grocy</literal> user which contains + the application's state. + ''; + }; + + settings = { + currency = mkOption { + type = types.str; + default = "USD"; + example = "EUR"; + description = '' + ISO 4217 code for the currency to display. + ''; + }; + + culture = mkOption { + type = types.enum [ "de" "en" "da" "en_GB" "es" "fr" "hu" "it" "nl" "no" "pl" "pt_BR" "ru" "sk_SK" "sv_SE" "tr" ]; + default = "en"; + description = '' + Display language of the frontend. + ''; + }; + + calendar = { + showWeekNumber = mkOption { + default = true; + type = types.bool; + description = '' + Show the number of the weeks in the calendar views. + ''; + }; + firstDayOfWeek = mkOption { + default = null; + type = types.nullOr (types.enum (range 0 6)); + description = '' + Which day of the week (0=Sunday, 1=Monday etc.) should be the + first day. + ''; + }; + }; + }; + }; + + config = mkIf cfg.enable { + environment.etc."grocy/config.php".text = '' + <?php + Setting('CULTURE', '${cfg.settings.culture}'); + Setting('CURRENCY', '${cfg.settings.currency}'); + Setting('CALENDAR_FIRST_DAY_OF_WEEK', '${toString cfg.settings.calendar.firstDayOfWeek}'); + Setting('CALENDAR_SHOW_WEEK_OF_YEAR', ${boolToString cfg.settings.calendar.showWeekNumber}); + ''; + + users.users.grocy = { + isSystemUser = true; + createHome = true; + home = cfg.dataDir; + group = "nginx"; + }; + + systemd.tmpfiles.rules = map ( + dirName: "d '${cfg.dataDir}/${dirName}' - grocy nginx - -" + ) [ "viewcache" "plugins" "settingoverrides" "storage" ]; + + services.phpfpm.pools.grocy = { + user = "grocy"; + group = "nginx"; + + # PHP 7.3 is the only version which is supported/tested by upstream: + # https://github.com/grocy/grocy/blob/v2.6.0/README.md#how-to-install + phpPackage = pkgs.php73; + + inherit (cfg.phpfpm) settings; + + phpEnv = { + GROCY_CONFIG_FILE = "/etc/grocy/config.php"; + GROCY_DB_FILE = "${cfg.dataDir}/grocy.db"; + GROCY_STORAGE_DIR = "${cfg.dataDir}/storage"; + GROCY_PLUGIN_DIR = "${cfg.dataDir}/plugins"; + GROCY_CACHE_DIR = "${cfg.dataDir}/viewcache"; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."${cfg.hostName}" = mkMerge [ + { root = "${pkgs.grocy}/public"; + locations."/".extraConfig = '' + rewrite ^ /index.php; + ''; + locations."~ \\.php$".extraConfig = '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools.grocy.socket}; + include ${config.services.nginx.package}/conf/fastcgi.conf; + include ${config.services.nginx.package}/conf/fastcgi_params; + ''; + locations."~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = '' + add_header Cache-Control "public, max-age=15778463"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header Referrer-Policy no-referrer; + access_log off; + ''; + extraConfig = '' + try_files $uri /index.php; + ''; + } + (mkIf cfg.nginx.enableSSL { + enableACME = true; + forceSSL = true; + }) + ]; + }; + }; + + meta = { + maintainers = with maintainers; [ ma27 ]; + doc = ./grocy.xml; + }; +} diff --git a/nixos/modules/services/web-apps/grocy.xml b/nixos/modules/services/web-apps/grocy.xml new file mode 100644 index 0000000000000..fdf6d00f4b123 --- /dev/null +++ b/nixos/modules/services/web-apps/grocy.xml @@ -0,0 +1,77 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-grocy"> + + <title>Grocy</title> + <para> + <link xlink:href="https://grocy.info/">Grocy</link> is a web-based self-hosted groceries + & household management solution for your home. + </para> + + <section xml:id="module-services-grocy-basic-usage"> + <title>Basic usage</title> + <para> + A very basic configuration may look like this: +<programlisting>{ pkgs, ... }: +{ + services.grocy = { + <link linkend="opt-services.grocy.enable">enable</link> = true; + <link linkend="opt-services.grocy.hostName">hostName</link> = "grocy.tld"; + }; +}</programlisting> + This configures a simple vhost using <link linkend="opt-services.nginx.enable">nginx</link> + which listens to <literal>grocy.tld</literal> with fully configured ACME/LE (this can be + disabled by setting <link linkend="opt-services.grocy.nginx.enableSSL">services.grocy.nginx.enableSSL</link> + to <literal>false</literal>). After the initial setup the credentials <literal>admin:admin</literal> + can be used to login. + </para> + <para> + The application's state is persisted at <literal>/var/lib/grocy/grocy.db</literal> in a + <package>sqlite3</package> database. The migration is applied when requesting the <literal>/</literal>-route + of the application. + </para> + </section> + + <section xml:id="module-services-grocy-settings"> + <title>Settings</title> + <para> + The configuration for <literal>grocy</literal> is located at <literal>/etc/grocy/config.php</literal>. + By default, the following settings can be defined in the NixOS-configuration: +<programlisting>{ pkgs, ... }: +{ + services.grocy.settings = { + # The default currency in the system for invoices etc. + # Please note that exchange rates aren't taken into account, this + # is just the setting for what's shown in the frontend. + <link linkend="opt-services.grocy.settings.currency">currency</link> = "EUR"; + + # The display language (and locale configuration) for grocy. + <link linkend="opt-services.grocy.settings.currency">culture</link> = "de"; + + calendar = { + # Whether or not to show the week-numbers + # in the calendar. + <link linkend="opt-services.grocy.settings.calendar.showWeekNumber">showWeekNumber</link> = true; + + # Index of the first day to be shown in the calendar (0=Sunday, 1=Monday, + # 2=Tuesday and so on). + <link linkend="opt-services.grocy.settings.calendar.firstDayOfWeek">firstDayOfWeek</link> = 2; + }; + }; +}</programlisting> + </para> + <para> + If you want to alter the configuration file on your own, you can do this manually with + an expression like this: +<programlisting>{ lib, ... }: +{ + environment.etc."grocy/config.php".text = lib.mkAfter '' + // Arbitrary PHP code in grocy's configuration file + ''; +}</programlisting> + </para> + </section> + +</chapter> diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index e1c299b8413e5..8e938e57e67fb 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -96,6 +96,7 @@ in freeswitch = handleTest ./freeswitch.nix {}; fsck = handleTest ./fsck.nix {}; gotify-server = handleTest ./gotify-server.nix {}; + grocy = handleTest ./grocy.nix {}; gitea = handleTest ./gitea.nix {}; gitlab = handleTest ./gitlab.nix {}; gitolite = handleTest ./gitolite.nix {}; diff --git a/nixos/tests/grocy.nix b/nixos/tests/grocy.nix new file mode 100644 index 0000000000000..7fa479ed2c42e --- /dev/null +++ b/nixos/tests/grocy.nix @@ -0,0 +1,47 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "grocy"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ ma27 ]; + }; + + machine = { pkgs, ... }: { + services.grocy = { + enable = true; + hostName = "localhost"; + nginx.enableSSL = false; + }; + environment.systemPackages = [ pkgs.jq ]; + }; + + testScript = '' + machine.start() + machine.wait_for_open_port(80) + machine.wait_for_unit("multi-user.target") + + machine.succeed("curl -sSf http://localhost") + + machine.succeed( + "curl -c cookies -sSf -X POST http://localhost/login -d 'username=admin&password=admin'" + ) + + cookie = machine.succeed( + "grep -v '^#' cookies | awk '{ print $7 }' | sed -e '/^$/d' | perl -pe 'chomp'" + ) + + machine.succeed( + f"curl -sSf -X POST http://localhost/api/objects/tasks -b 'grocy_session={cookie}' " + + '-d \'{"assigned_to_user_id":1,"name":"Test Task","due_date":"1970-01-01"}\''' + + " --header 'Content-Type: application/json'" + ) + + task_name = machine.succeed( + f"curl -sSf http://localhost/api/tasks -b 'grocy_session={cookie}' --header 'Accept: application/json' | jq '.[].name' | xargs echo | perl -pe 'chomp'" + ) + + assert task_name == "Test Task" + + machine.succeed("curl -sSfI http://localhost/api/tasks 2>&1 | grep '401 Unauthorized'") + + machine.shutdown() + ''; +}) |