at 24.11-pre 12 kB view raw
1{ config, pkgs, lib, ... }: 2 3let 4 cfg = config.services.anuko-time-tracker; 5 configFile = let 6 smtpPassword = if cfg.settings.email.smtpPasswordFile == null 7 then "''" 8 else "trim(file_get_contents('${cfg.settings.email.smtpPasswordFile}'))"; 9 10 in pkgs.writeText "config.php" '' 11 <?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'); 36 ''; 37 package = pkgs.stdenv.mkDerivation rec { 38 pname = "anuko-time-tracker"; 39 inherit (src) version; 40 src = cfg.package; 41 installPhase = '' 42 mkdir -p $out 43 cp -r * $out/ 44 45 # Link config file 46 ln -s ${configFile} $out/WEB-INF/config.php 47 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 51 52 # Remove unsafe dbinstall.php 53 rm -f $out/dbinstall.php 54 ''; 55 }; 56in 57{ 58 options.services.anuko-time-tracker = { 59 enable = lib.mkEnableOption "Anuko Time Tracker"; 60 61 package = lib.mkPackageOption pkgs "anuko-time-tracker" {}; 62 63 database = { 64 createLocally = lib.mkOption { 65 type = lib.types.bool; 66 default = true; 67 description = "Create the database and database user locally."; 68 }; 69 70 host = lib.mkOption { 71 type = lib.types.str; 72 description = "Database host."; 73 default = "localhost"; 74 }; 75 76 name = lib.mkOption { 77 type = lib.types.str; 78 description = "Database name."; 79 default = "anuko_time_tracker"; 80 }; 81 82 user = lib.mkOption { 83 type = lib.types.str; 84 description = "Database username."; 85 default = "anuko_time_tracker"; 86 }; 87 88 passwordFile = lib.mkOption { 89 type = lib.types.nullOr lib.types.str; 90 description = "Database user password file."; 91 default = null; 92 }; 93 }; 94 95 poolConfig = lib.mkOption { 96 type = lib.types.attrsOf (lib.types.oneOf [ lib.types.str lib.types.int lib.types.bool ]); 97 default = { 98 "pm" = "dynamic"; 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; 104 }; 105 description = '' 106 Options for Anuko Time Tracker's PHP-FPM pool. 107 ''; 108 }; 109 110 hostname = lib.mkOption { 111 type = lib.types.str; 112 default = 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"; 118 description = '' 119 The hostname to serve Anuko Time Tracker on. 120 ''; 121 }; 122 123 nginx = lib.mkOption { 124 type = lib.types.submodule ( 125 lib.recursiveUpdate 126 (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {} 127 ); 128 default = {}; 129 example = lib.literalExpression '' 130 { 131 serverAliases = [ 132 "anuko.''${config.networking.domain}" 133 ]; 134 135 # To enable encryption and let let's encrypt take care of certificate 136 forceSSL = true; 137 enableACME = true; 138 } 139 ''; 140 description = '' 141 With this option, you can customize the Nginx virtualHost settings. 142 ''; 143 }; 144 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"; 150 }; 151 152 user = lib.mkOption { 153 type = lib.types.str; 154 default = "anuko_time_tracker"; 155 description = "User under which Anuko Time Tracker runs."; 156 }; 157 158 settings = { 159 multiorgMode = lib.mkOption { 160 type = lib.types.bool; 161 default = true; 162 description = '' 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). 165 ''; 166 }; 167 168 emailRequired = lib.mkOption { 169 type = lib.types.bool; 170 default = false; 171 description = "Defines whether an email is required for new registrations."; 172 }; 173 174 weekendStartDay = lib.mkOption { 175 type = lib.types.int; 176 default = 6; 177 description = '' 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 180 weekend days. 181 ''; 182 }; 183 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"; 188 }; 189 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"; 194 }; 195 196 email = { 197 sender = lib.mkOption { 198 type = lib.types.str; 199 description = "Default sender for mail."; 200 default = "Anuko Time Tracker <bounces@example.com>"; 201 }; 202 203 mode = lib.mkOption { 204 type = lib.types.str; 205 description = "Mail sending mode. Can be 'mail' or 'smtp'."; 206 default = "smtp"; 207 }; 208 209 smtpHost = lib.mkOption { 210 type = lib.types.str; 211 description = "MTA hostname."; 212 default = "localhost"; 213 }; 214 215 smtpPort = lib.mkOption { 216 type = lib.types.int; 217 description = "MTA port."; 218 default = 25; 219 }; 220 221 smtpUser = lib.mkOption { 222 type = lib.types.str; 223 description = "MTA authentication username."; 224 default = ""; 225 }; 226 227 smtpAuth = lib.mkOption { 228 type = lib.types.bool; 229 default = false; 230 description = "MTA requires authentication."; 231 }; 232 233 smtpPasswordFile = lib.mkOption { 234 type = lib.types.nullOr lib.types.path; 235 default = null; 236 example = "/var/lib/anuko-time-tracker/secrets/smtp-password"; 237 description = '' 238 Path to file containing the MTA authentication password. 239 ''; 240 }; 241 242 smtpDebug = lib.mkOption { 243 type = lib.types.bool; 244 default = false; 245 description = "Debug mail sending."; 246 }; 247 }; 248 249 defaultLanguage = lib.mkOption { 250 type = lib.types.str; 251 description = '' 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. 255 ''; 256 default = ""; 257 example = "nl"; 258 }; 259 260 defaultCurrency = lib.mkOption { 261 type = lib.types.str; 262 description = '' 263 Defines a default currency symbol for new groups. 264 Use , £, a more specific dollar like US$, CAD, etc. 265 ''; 266 default = "$"; 267 example = ""; 268 }; 269 270 exportDecimalDuration = lib.mkOption { 271 type = lib.types.bool; 272 default = true; 273 description = '' 274 Defines whether time duration values are decimal in CSV and XML data 275 exports (1.25 vs 1:15). 276 ''; 277 }; 278 279 reportFooter = lib.mkOption { 280 type = lib.types.bool; 281 default = true; 282 description = "Defines whether to use a footer on reports."; 283 }; 284 }; 285 }; 286 287 config = lib.mkIf cfg.enable { 288 289 assertions = [ 290 { 291 assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; 292 message = '' 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. 295 ''; 296 } 297 { 298 assertion = cfg.settings.email.smtpAuth -> (cfg.settings.email.smtpPasswordFile != null); 299 message = '' 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. 302 ''; 303 } 304 ]; 305 306 services.phpfpm = { 307 pools.anuko-time-tracker = { 308 inherit (cfg) user; 309 group = config.services.nginx.group; 310 settings = { 311 "listen.owner" = config.services.nginx.user; 312 "listen.group" = config.services.nginx.group; 313 } // cfg.poolConfig; 314 }; 315 }; 316 317 services.nginx = { 318 enable = lib.mkDefault true; 319 recommendedTlsSettings = true; 320 recommendedOptimisation = true; 321 recommendedGzipSettings = true; 322 virtualHosts."${cfg.hostname}" = lib.mkMerge [ 323 cfg.nginx 324 { 325 root = lib.mkForce "${package}"; 326 locations = { 327 "/".index = "index.php"; 328 "~ [^/]\\.php(/|$)" = { 329 extraConfig = '' 330 fastcgi_split_path_info ^(.+?\.php)(/.*)$; 331 fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket}; 332 ''; 333 }; 334 }; 335 } 336 ]; 337 }; 338 339 services.mysql = lib.mkIf cfg.database.createLocally { 340 enable = lib.mkDefault true; 341 package = lib.mkDefault pkgs.mariadb; 342 ensureDatabases = [ cfg.database.name ]; 343 ensureUsers = [{ 344 name = cfg.database.user; 345 ensurePermissions = { 346 "${cfg.database.name}.*" = "ALL PRIVILEGES"; 347 }; 348 }]; 349 }; 350 351 systemd = { 352 services = { 353 anuko-time-tracker-setup-database = lib.mkIf cfg.database.createLocally { 354 description = "Set up Anuko Time Tracker database"; 355 serviceConfig = { 356 Type = "oneshot"; 357 RemainAfterExit = true; 358 }; 359 wantedBy = [ "phpfpm-anuko-time-tracker.service" ]; 360 after = [ "mysql.service" ]; 361 script = 362 let 363 mysql = "${config.services.mysql.package}/bin/mysql"; 364 in 365 '' 366 if [ ! -f ${cfg.dataDir}/.dbexists ]; then 367 # Load database schema provided with package 368 ${mysql} ${cfg.database.name} < ${cfg.package}/mysql.sql 369 370 touch ${cfg.dataDir}/.dbexists 371 fi 372 ''; 373 }; 374 }; 375 tmpfiles.rules = [ 376 "d ${cfg.dataDir} 0750 ${cfg.user} ${config.services.nginx.group} -" 377 "d ${cfg.dataDir}/templates_c 0750 ${cfg.user} ${config.services.nginx.group} -" 378 ]; 379 }; 380 381 users.users."${cfg.user}" = { 382 isSystemUser = true; 383 group = config.services.nginx.group; 384 }; 385 }; 386 387 meta.maintainers = with lib.maintainers; [ michaelshmitty ]; 388}