nixos/grocy: init module
Co-authored-by: elseym <elseym@me.com>
This commit is contained in:
parent
3d051f49ba
commit
13f7b75553
|
@ -814,6 +814,7 @@
|
||||||
./services/web-apps/dokuwiki.nix
|
./services/web-apps/dokuwiki.nix
|
||||||
./services/web-apps/frab.nix
|
./services/web-apps/frab.nix
|
||||||
./services/web-apps/gotify-server.nix
|
./services/web-apps/gotify-server.nix
|
||||||
|
./services/web-apps/grocy.nix
|
||||||
./services/web-apps/icingaweb2/icingaweb2.nix
|
./services/web-apps/icingaweb2/icingaweb2.nix
|
||||||
./services/web-apps/icingaweb2/module-monitoring.nix
|
./services/web-apps/icingaweb2/module-monitoring.nix
|
||||||
./services/web-apps/ihatemoney
|
./services/web-apps/ihatemoney
|
||||||
|
|
172
nixos/modules/services/web-apps/grocy.nix
Normal file
172
nixos/modules/services/web-apps/grocy.nix
Normal file
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
77
nixos/modules/services/web-apps/grocy.xml
Normal file
77
nixos/modules/services/web-apps/grocy.xml
Normal file
|
@ -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>
|
|
@ -96,6 +96,7 @@ in
|
||||||
freeswitch = handleTest ./freeswitch.nix {};
|
freeswitch = handleTest ./freeswitch.nix {};
|
||||||
fsck = handleTest ./fsck.nix {};
|
fsck = handleTest ./fsck.nix {};
|
||||||
gotify-server = handleTest ./gotify-server.nix {};
|
gotify-server = handleTest ./gotify-server.nix {};
|
||||||
|
grocy = handleTest ./grocy.nix {};
|
||||||
gitea = handleTest ./gitea.nix {};
|
gitea = handleTest ./gitea.nix {};
|
||||||
gitlab = handleTest ./gitlab.nix {};
|
gitlab = handleTest ./gitlab.nix {};
|
||||||
gitolite = handleTest ./gitolite.nix {};
|
gitolite = handleTest ./gitolite.nix {};
|
||||||
|
|
47
nixos/tests/grocy.nix
Normal file
47
nixos/tests/grocy.nix
Normal file
|
@ -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()
|
||||||
|
'';
|
||||||
|
})
|
Loading…
Reference in a new issue