diff options
author | Michael Smith <shmitty@protonmail.com> | 2023-06-27 12:30:06 +0200 |
---|---|---|
committer | Michael Smith <shmitty@protonmail.com> | 2023-06-27 12:30:33 +0200 |
commit | 7532dbaa32f661f8f8743e24629516f853e39f9e (patch) | |
tree | 725f3443bb30aa4c73b643877c505672de2c2de6 /nixos | |
parent | 30874bced705e3679e5ab044895e51c89c6921ba (diff) |
nixos/anuko-time-tracker: init
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2311.section.md | 2 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/anuko-time-tracker.nix | 354 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/anuko-time-tracker.nix | 17 |
5 files changed, 375 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md index 00d52376b18a8..70613c392a371 100644 --- a/nixos/doc/manual/release-notes/rl-2311.section.md +++ b/nixos/doc/manual/release-notes/rl-2311.section.md @@ -16,6 +16,8 @@ - [GoToSocial](https://gotosocial.org/), an ActivityPub social network server, written in Golang. Available as [services.gotosocial](#opt-services.gotosocial.enable). +- [Anuko Time Tracker](https://github.com/anuko/timetracker), a simple, easy to use, open source time tracking system. Available as [services.anuko-time-tracker](#opt-services.anuko-time-tracker.enable). + - [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable). - [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 43fcc68ded42a..ebf52804d4ec7 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1168,6 +1168,7 @@ ./services/wayland/cage.nix ./services/web-apps/akkoma.nix ./services/web-apps/alps.nix + ./services/web-apps/anuko-time-tracker.nix ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix diff --git a/nixos/modules/services/web-apps/anuko-time-tracker.nix b/nixos/modules/services/web-apps/anuko-time-tracker.nix new file mode 100644 index 0000000000000..c50a0328e34d8 --- /dev/null +++ b/nixos/modules/services/web-apps/anuko-time-tracker.nix @@ -0,0 +1,354 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.anuko-time-tracker; + configFile = let + smtpPassword = if cfg.settings.email.smtpPasswordFile == null + then "''" + else "trim(file_get_contents('${cfg.settings.email.smtpPasswordFile}'))"; + + in pkgs.writeText "config.php" '' + <?php + // Set include path for PEAR and its modules, which we include in the distribution. + // Updated for the correct location in the nix store. + set_include_path('${cfg.package}/WEB-INF/lib/pear' . PATH_SEPARATOR . get_include_path()); + define('DSN', 'mysqli://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}?charset=utf8mb4'); + define('MULTIORG_MODE', ${lib.boolToString cfg.settings.multiorgMode}); + define('EMAIL_REQUIRED', ${lib.boolToString cfg.settings.emailRequired}); + define('WEEKEND_START_DAY', ${toString cfg.settings.weekendStartDay}); + define('FORUM_LINK', '${cfg.settings.forumLink}'); + define('HELP_LINK', '${cfg.settings.helpLink}'); + define('SENDER', '${cfg.settings.email.sender}'); + define('MAIL_MODE', '${cfg.settings.email.mode}'); + define('MAIL_SMTP_HOST', '${toString cfg.settings.email.smtpHost}'); + define('MAIL_SMTP_PORT', '${toString cfg.settings.email.smtpPort}'); + define('MAIL_SMTP_USER', '${cfg.settings.email.smtpUser}'); + define('MAIL_SMTP_PASSWORD', ${smtpPassword}); + define('MAIL_SMTP_AUTH', ${lib.boolToString cfg.settings.email.smtpAuth}); + define('MAIL_SMTP_DEBUG', ${lib.boolToString cfg.settings.email.smtpDebug}); + define('DEFAULT_CSS', 'default.css'); + define('RTL_CSS', 'rtl.css'); // For right to left languages. + define('LANG_DEFAULT', '${cfg.settings.defaultLanguage}'); + define('CURRENCY_DEFAULT', '${cfg.settings.defaultCurrency}'); + define('EXPORT_DECIMAL_DURATION', ${lib.boolToString cfg.settings.exportDecimalDuration}); + define('REPORT_FOOTER', ${lib.boolToString cfg.settings.reportFooter}); + define('AUTH_MODULE', 'db'); + ''; + package = pkgs.stdenv.mkDerivation rec { + pname = "anuko-time-tracker"; + inherit (src) version; + src = cfg.package; + installPhase = '' + mkdir -p $out + cp -r * $out/ + + ln -s ${configFile} $out/WEB-INF/config.php + + # Link writable templates_c directory + rm -rf $out/WEB-INF/templates_c + ln -s ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c + + # ln -fs ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c + ''; + }; +in +{ + options.services.anuko-time-tracker = { + enable = lib.mkEnableOption (lib.mdDoc "Anuko Time Tracker"); + + package = lib.mkPackageOptionMD pkgs "anuko-time-tracker" {}; + + database = { + createLocally = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc "Create the database and database user locally."; + }; + + host = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Database host."; + default = "localhost"; + }; + + name = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Database name."; + default = "anuko_time_tracker"; + }; + + user = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Database username."; + default = "anuko_time_tracker"; + }; + + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = lib.mdDoc "Database user password file."; + default = null; + }; + }; + + poolConfig = lib.mkOption { + type = lib.types.attrsOf (lib.types.oneOf [ lib.types.str lib.types.int lib.types.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 = lib.mdDoc '' + Options for Anuko Time Tracker's PHP-FPM pool. + ''; + }; + + dataDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/anuko-time-tracker"; + description = lib.mdDoc "Default data folder for Anuko Time Tracker."; + example = "/mnt/anuko-time-tracker"; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "anuko_time_tracker"; + description = lib.mdDoc "User under which Anuko Time Tracker runs."; + }; + + virtualHost = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = "localhost"; + description = lib.mdDoc '' + Name of the nginx virtualhost to use and setup. If null, do not setup + any virtualhost. + ''; + }; + + settings = { + multiorgMode = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc '' + Defines whether users see the Register option in the menu of Time Tracker that allows them + to self-register and create new organizations (top groups). + ''; + }; + + emailRequired = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc "Defines whether an email is required for new registrations."; + }; + + weekendStartDay = lib.mkOption { + type = lib.types.int; + default = 6; + description = lib.mdDoc '' + This option defines which days are highlighted with weekend color. + 6 means Saturday. For Saudi Arabia, etc. set it to 4 for Thursday and Friday to be + weekend days. + ''; + }; + + forumLink = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Forum link from the main menu."; + default = "https://www.anuko.com/forum/viewforum.php?f=4"; + }; + + helpLink = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Help link from the main menu."; + default = "https://www.anuko.com/time-tracker/user-guide/index.htm"; + }; + + email = { + sender = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Default sender for mail."; + default = "Anuko Time Tracker <bounces@example.com>"; + }; + + mode = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "Mail sending mode. Can be 'mail' or 'smtp'."; + default = "smtp"; + }; + + smtpHost = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "MTA hostname."; + default = "localhost"; + }; + + smtpPort = lib.mkOption { + type = lib.types.int; + description = lib.mdDoc "MTA port."; + default = 25; + }; + + smtpUser = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc "MTA authentication username."; + default = ""; + }; + + smtpAuth = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc "MTA requires authentication."; + }; + + smtpPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/var/lib/anuko-time-tracker/secrets/smtp-password"; + description = lib.mdDoc '' + Path to file containing the MTA authentication password. + ''; + }; + + smtpDebug = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc "Debug mail sending."; + }; + }; + + defaultLanguage = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc '' + Defines Anuko Time Tracker default language. It is used on Time Tracker login page. + After login, a language set for user group is used. + Empty string means the language is defined by user browser. + ''; + default = ""; + example = "nl"; + }; + + defaultCurrency = lib.mkOption { + type = lib.types.str; + description = lib.mdDoc '' + Defines a default currency symbol for new groups. + Use €, £, a more specific dollar like US$, CAD, etc. + ''; + default = "$"; + example = "€"; + }; + + exportDecimalDuration = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc '' + Defines whether time duration values are decimal in CSV and XML data + exports (1.25 vs 1:15). + ''; + }; + + reportFooter = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc "Defines whether to use a footer on reports."; + }; + }; + }; + + config = lib.mkIf cfg.enable { + + assertions = [ + { + assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; + message = '' + <option>services.anuko-time-tracker.database.passwordFile</option> cannot be specified if + <option>services.anuko-time-tracker.database.createLocally</option> is set to true. + ''; + } + { + assertion = cfg.settings.email.smtpAuth -> (cfg.settings.email.smtpPasswordFile != null); + message = '' + <option>services.anuko-time-tracker.settings.email.smtpPasswordFile</option> needs to be set if + <option>services.anuko-time-tracker.settings.email.smtpAuth</option> is enabled. + ''; + } + ]; + + services.phpfpm = { + pools.anuko-time-tracker = { + inherit (cfg) user; + group = config.services.nginx.group; + settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + } // cfg.poolConfig; + }; + }; + + services.nginx = lib.mkIf (cfg.virtualHost != null) { + enable = true; + virtualHosts = { + "${cfg.virtualHost}" = { + root = lib.mkForce "${package}"; + locations."/".index = "index.php"; + locations."~ [^/]\\.php(/|$)" = { + extraConfig = '' + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket}; + ''; + }; + }; + }; + }; + + services.mysql = lib.mkIf cfg.database.createLocally { + enable = lib.mkDefault true; + package = lib.mkDefault pkgs.mariadb; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [{ + name = cfg.database.user; + ensurePermissions = { + "${cfg.database.name}.*" = "ALL PRIVILEGES"; + }; + }]; + }; + + systemd = { + services = { + anuko-time-tracker-setup-database = lib.mkIf cfg.database.createLocally { + description = "Set up Anuko Time Tracker database"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + wantedBy = [ "phpfpm-anuko-time-tracker.service" ]; + after = [ "mysql.service" ]; + script = + let + mysql = "${config.services.mysql.package}/bin/mysql"; + in + '' + if [ ! -f ${cfg.dataDir}/.dbexists ]; then + # Load database schema provided with package + ${mysql} ${cfg.database.name} < ${cfg.package}/mysql.sql + + touch ${cfg.dataDir}/.dbexists + fi + ''; + }; + }; + tmpfiles.rules = [ + "d ${cfg.dataDir} 0750 ${cfg.user} ${config.services.nginx.group} -" + "d ${cfg.dataDir}/templates_c 0750 ${cfg.user} ${config.services.nginx.group} -" + ]; + }; + + users.users."${cfg.user}" = { + isSystemUser = true; + group = config.services.nginx.group; + }; + }; + + meta.maintainers = with lib.maintainers; [ michaelshmitty ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 6e9c893c809e4..068e3ce7b2487 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -107,6 +107,7 @@ in { allTerminfo = handleTest ./all-terminfo.nix {}; alps = handleTest ./alps.nix {}; amazon-init-shell = handleTest ./amazon-init-shell.nix {}; + anuko-time-tracker = handleTest ./anuko-time-tracker.nix {}; apcupsd = handleTest ./apcupsd.nix {}; apfs = runTest ./apfs.nix; apparmor = handleTest ./apparmor.nix {}; diff --git a/nixos/tests/anuko-time-tracker.nix b/nixos/tests/anuko-time-tracker.nix new file mode 100644 index 0000000000000..18c3bf5cf6957 --- /dev/null +++ b/nixos/tests/anuko-time-tracker.nix @@ -0,0 +1,17 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "anuko-time-tracker"; + meta = { + maintainers = with pkgs.lib.maintainers; [ michaelshmitty ]; + }; + nodes = { + machine = { + services.anuko-time-tracker.enable = true; + }; + }; + testScript = '' + start_all() + machine.wait_for_unit("phpfpm-anuko-time-tracker") + machine.wait_for_open_port(80); + machine.wait_until_succeeds("curl -s --fail -L http://localhost/time.php | grep 'Anuko Time Tracker'") + ''; +}) |