1 { config, pkgs, lib, ... }:
4 cfg = config.services.anuko-time-tracker;
6 smtpPassword = if cfg.settings.email.smtpPasswordFile == null
8 else "trim(file_get_contents('${cfg.settings.email.smtpPasswordFile}'))";
10 in pkgs.writeText "config.php" ''
12 // Set include path for PEAR and its modules, which we include in the distribution.
13 // Updated for the correct location in the nix store.
14 set_include_path('${cfg.package}/WEB-INF/lib/pear' . PATH_SEPARATOR . get_include_path());
15 define('DSN', 'mysqli://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}?charset=utf8mb4');
16 define('MULTIORG_MODE', ${lib.boolToString cfg.settings.multiorgMode});
17 define('EMAIL_REQUIRED', ${lib.boolToString cfg.settings.emailRequired});
18 define('WEEKEND_START_DAY', ${toString cfg.settings.weekendStartDay});
19 define('FORUM_LINK', '${cfg.settings.forumLink}');
20 define('HELP_LINK', '${cfg.settings.helpLink}');
21 define('SENDER', '${cfg.settings.email.sender}');
22 define('MAIL_MODE', '${cfg.settings.email.mode}');
23 define('MAIL_SMTP_HOST', '${toString cfg.settings.email.smtpHost}');
24 define('MAIL_SMTP_PORT', '${toString cfg.settings.email.smtpPort}');
25 define('MAIL_SMTP_USER', '${cfg.settings.email.smtpUser}');
26 define('MAIL_SMTP_PASSWORD', ${smtpPassword});
27 define('MAIL_SMTP_AUTH', ${lib.boolToString cfg.settings.email.smtpAuth});
28 define('MAIL_SMTP_DEBUG', ${lib.boolToString cfg.settings.email.smtpDebug});
29 define('DEFAULT_CSS', 'default.css');
30 define('RTL_CSS', 'rtl.css'); // For right to left languages.
31 define('LANG_DEFAULT', '${cfg.settings.defaultLanguage}');
32 define('CURRENCY_DEFAULT', '${cfg.settings.defaultCurrency}');
33 define('EXPORT_DECIMAL_DURATION', ${lib.boolToString cfg.settings.exportDecimalDuration});
34 define('REPORT_FOOTER', ${lib.boolToString cfg.settings.reportFooter});
35 define('AUTH_MODULE', 'db');
37 package = pkgs.stdenv.mkDerivation rec {
38 pname = "anuko-time-tracker";
39 inherit (src) version;
46 ln -s ${configFile} $out/WEB-INF/config.php
48 # Link writable templates_c directory
49 rm -rf $out/WEB-INF/templates_c
50 ln -s ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c
52 # Remove unsafe dbinstall.php
53 rm -f $out/dbinstall.php
58 options.services.anuko-time-tracker = {
59 enable = lib.mkEnableOption "Anuko Time Tracker";
61 package = lib.mkPackageOption pkgs "anuko-time-tracker" {};
64 createLocally = lib.mkOption {
65 type = lib.types.bool;
67 description = "Create the database and database user locally.";
72 description = "Database host.";
73 default = "localhost";
78 description = "Database name.";
79 default = "anuko_time_tracker";
84 description = "Database username.";
85 default = "anuko_time_tracker";
88 passwordFile = lib.mkOption {
89 type = lib.types.nullOr lib.types.str;
90 description = "Database user password file.";
95 poolConfig = lib.mkOption {
96 type = lib.types.attrsOf (lib.types.oneOf [ lib.types.str lib.types.int lib.types.bool ]);
99 "pm.max_children" = 32;
100 "pm.start_servers" = 2;
101 "pm.min_spare_servers" = 2;
102 "pm.max_spare_servers" = 4;
103 "pm.max_requests" = 500;
106 Options for Anuko Time Tracker's PHP-FPM pool.
110 hostname = lib.mkOption {
111 type = lib.types.str;
113 if config.networking.domain != null
114 then config.networking.fqdn
115 else config.networking.hostName;
116 defaultText = lib.literalExpression "config.networking.fqdn";
117 example = "anuko.example.com";
119 The hostname to serve Anuko Time Tracker on.
123 nginx = lib.mkOption {
124 type = lib.types.submodule (
126 (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {}
129 example = lib.literalExpression ''
132 "anuko.''${config.networking.domain}"
135 # To enable encryption and let let's encrypt take care of certificate
141 With this option, you can customize the Nginx virtualHost settings.
145 dataDir = lib.mkOption {
146 type = lib.types.str;
147 default = "/var/lib/anuko-time-tracker";
148 description = "Default data folder for Anuko Time Tracker.";
149 example = "/mnt/anuko-time-tracker";
152 user = lib.mkOption {
153 type = lib.types.str;
154 default = "anuko_time_tracker";
155 description = "User under which Anuko Time Tracker runs.";
159 multiorgMode = lib.mkOption {
160 type = lib.types.bool;
163 Defines whether users see the Register option in the menu of Time Tracker that allows them
164 to self-register and create new organizations (top groups).
168 emailRequired = lib.mkOption {
169 type = lib.types.bool;
171 description = "Defines whether an email is required for new registrations.";
174 weekendStartDay = lib.mkOption {
175 type = lib.types.int;
178 This option defines which days are highlighted with weekend color.
179 6 means Saturday. For Saudi Arabia, etc. set it to 4 for Thursday and Friday to be
184 forumLink = lib.mkOption {
185 type = lib.types.str;
186 description = "Forum link from the main menu.";
187 default = "https://www.anuko.com/forum/viewforum.php?f=4";
190 helpLink = lib.mkOption {
191 type = lib.types.str;
192 description = "Help link from the main menu.";
193 default = "https://www.anuko.com/time-tracker/user-guide/index.htm";
197 sender = lib.mkOption {
198 type = lib.types.str;
199 description = "Default sender for mail.";
200 default = "Anuko Time Tracker <bounces@example.com>";
203 mode = lib.mkOption {
204 type = lib.types.str;
205 description = "Mail sending mode. Can be 'mail' or 'smtp'.";
209 smtpHost = lib.mkOption {
210 type = lib.types.str;
211 description = "MTA hostname.";
212 default = "localhost";
215 smtpPort = lib.mkOption {
216 type = lib.types.int;
217 description = "MTA port.";
221 smtpUser = lib.mkOption {
222 type = lib.types.str;
223 description = "MTA authentication username.";
227 smtpAuth = lib.mkOption {
228 type = lib.types.bool;
230 description = "MTA requires authentication.";
233 smtpPasswordFile = lib.mkOption {
234 type = lib.types.nullOr lib.types.path;
236 example = "/var/lib/anuko-time-tracker/secrets/smtp-password";
238 Path to file containing the MTA authentication password.
242 smtpDebug = lib.mkOption {
243 type = lib.types.bool;
245 description = "Debug mail sending.";
249 defaultLanguage = lib.mkOption {
250 type = lib.types.str;
252 Defines Anuko Time Tracker default language. It is used on Time Tracker login page.
253 After login, a language set for user group is used.
254 Empty string means the language is defined by user browser.
260 defaultCurrency = lib.mkOption {
261 type = lib.types.str;
263 Defines a default currency symbol for new groups.
264 Use €, £, a more specific dollar like US$, CAD, etc.
270 exportDecimalDuration = lib.mkOption {
271 type = lib.types.bool;
274 Defines whether time duration values are decimal in CSV and XML data
275 exports (1.25 vs 1:15).
279 reportFooter = lib.mkOption {
280 type = lib.types.bool;
282 description = "Defines whether to use a footer on reports.";
287 config = lib.mkIf cfg.enable {
291 assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
293 <option>services.anuko-time-tracker.database.passwordFile</option> cannot be specified if
294 <option>services.anuko-time-tracker.database.createLocally</option> is set to true.
298 assertion = cfg.settings.email.smtpAuth -> (cfg.settings.email.smtpPasswordFile != null);
300 <option>services.anuko-time-tracker.settings.email.smtpPasswordFile</option> needs to be set if
301 <option>services.anuko-time-tracker.settings.email.smtpAuth</option> is enabled.
307 pools.anuko-time-tracker = {
309 group = config.services.nginx.group;
311 "listen.owner" = config.services.nginx.user;
312 "listen.group" = config.services.nginx.group;
318 enable = lib.mkDefault true;
319 recommendedTlsSettings = true;
320 recommendedOptimisation = true;
321 recommendedGzipSettings = true;
322 virtualHosts."${cfg.hostname}" = lib.mkMerge [
325 root = lib.mkForce "${package}";
327 "/".index = "index.php";
328 "~ [^/]\\.php(/|$)" = {
330 fastcgi_split_path_info ^(.+?\.php)(/.*)$;
331 fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket};
339 services.mysql = lib.mkIf cfg.database.createLocally {
340 enable = lib.mkDefault true;
341 package = lib.mkDefault pkgs.mariadb;
342 ensureDatabases = [ cfg.database.name ];
344 name = cfg.database.user;
345 ensurePermissions = {
346 "${cfg.database.name}.*" = "ALL PRIVILEGES";
353 anuko-time-tracker-setup-database = lib.mkIf cfg.database.createLocally {
354 description = "Set up Anuko Time Tracker database";
357 RemainAfterExit = true;
359 wantedBy = [ "phpfpm-anuko-time-tracker.service" ];
360 after = [ "mysql.service" ];
363 mysql = "${config.services.mysql.package}/bin/mysql";
366 if [ ! -f ${cfg.dataDir}/.dbexists ]; then
367 # Load database schema provided with package
368 ${mysql} ${cfg.database.name} < ${cfg.package}/mysql.sql
370 touch ${cfg.dataDir}/.dbexists
376 "d ${cfg.dataDir} 0750 ${cfg.user} ${config.services.nginx.group} -"
377 "d ${cfg.dataDir}/templates_c 0750 ${cfg.user} ${config.services.nginx.group} -"
381 users.users."${cfg.user}" = {
383 group = config.services.nginx.group;
387 meta.maintainers = with lib.maintainers; [ michaelshmitty ];