1{
2 lib,
3 pkgs,
4 config,
5 ...
6}:
7with lib;
8let
9 cfg = config.services.hledger-web;
10in
11{
12 options.services.hledger-web = {
13
14 enable = mkEnableOption "hledger-web service";
15
16 serveApi = mkEnableOption "serving only the JSON web API, without the web UI";
17
18 host = mkOption {
19 type = types.str;
20 default = "127.0.0.1";
21 description = ''
22 Address to listen on.
23 '';
24 };
25
26 port = mkOption {
27 type = types.port;
28 default = 5000;
29 example = 80;
30 description = ''
31 Port to listen on.
32 '';
33 };
34
35 allow = mkOption {
36 type = types.enum [
37 "view"
38 "add"
39 "edit"
40 "sandstorm"
41 ];
42 default = "view";
43 description = ''
44 User's access level for changing data.
45
46 * view: view only permission.
47 * add: view and add permissions.
48 * edit: view, add, and edit permissions.
49 * sandstorm: permissions from the `X-Sandstorm-Permissions` request header.
50 '';
51 };
52
53 stateDir = mkOption {
54 type = types.path;
55 default = "/var/lib/hledger-web";
56 description = ''
57 Path the service has access to. If left as the default value this
58 directory will automatically be created before the hledger-web server
59 starts, otherwise the sysadmin is responsible for ensuring the
60 directory exists with appropriate ownership and permissions.
61 '';
62 };
63
64 journalFiles = mkOption {
65 type = types.listOf types.str;
66 default = [ ".hledger.journal" ];
67 description = ''
68 Paths to journal files relative to {option}`services.hledger-web.stateDir`.
69 '';
70 };
71
72 baseUrl = mkOption {
73 type = with types; nullOr str;
74 default = null;
75 example = "https://example.org";
76 description = ''
77 Base URL, when sharing over a network.
78 '';
79 };
80
81 extraOptions = mkOption {
82 type = types.listOf types.str;
83 default = [ ];
84 example = [ "--forecast" ];
85 description = ''
86 Extra command line arguments to pass to hledger-web.
87 '';
88 };
89
90 };
91
92 imports = [
93 (mkRemovedOptionModule [
94 "services"
95 "hledger-web"
96 "capabilities"
97 ] "This option has been replaced by new option `services.hledger-web.allow`.")
98 ];
99
100 config = mkIf cfg.enable {
101
102 users.users.hledger = {
103 name = "hledger";
104 group = "hledger";
105 isSystemUser = true;
106 home = cfg.stateDir;
107 useDefaultShell = true;
108 };
109
110 users.groups.hledger = { };
111
112 systemd.services.hledger-web =
113 let
114 serverArgs =
115 with cfg;
116 escapeShellArgs (
117 [
118 "--serve"
119 "--host=${host}"
120 "--port=${toString port}"
121 "--allow=${allow}"
122 (optionalString (cfg.baseUrl != null) "--base-url=${cfg.baseUrl}")
123 (optionalString (cfg.serveApi) "--serve-api")
124 ]
125 ++ (map (f: "--file=${stateDir}/${f}") cfg.journalFiles)
126 ++ extraOptions
127 );
128 in
129 {
130 description = "hledger-web - web-app for the hledger accounting tool.";
131 documentation = [
132 "info:hledger-web"
133 "man:hledger-web(1)"
134 "https://hledger.org/hledger-web.html"
135 ];
136 wantedBy = [ "multi-user.target" ];
137 after = [ "networking.target" ];
138 serviceConfig = mkMerge [
139 {
140 ExecStart = "${pkgs.hledger-web}/bin/hledger-web ${serverArgs}";
141 Restart = "always";
142 WorkingDirectory = cfg.stateDir;
143 User = "hledger";
144 Group = "hledger";
145 PrivateTmp = true;
146 }
147 (mkIf (cfg.stateDir == "/var/lib/hledger-web") {
148 StateDirectory = "hledger-web";
149 })
150 ];
151 };
152
153 };
154
155 meta.maintainers = with lib.maintainers; [
156 marijanp
157 erictapen
158 ];
159}