at 25.11-pre 12 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7 8let 9 cfg = config.services.anuko-time-tracker; 10 configFile = 11 let 12 smtpPassword = 13 if cfg.settings.email.smtpPasswordFile == null then 14 "''" 15 else 16 "trim(file_get_contents('${cfg.settings.email.smtpPasswordFile}'))"; 17 18 in 19 pkgs.writeText "config.php" '' 20 <?php 21 // Set include path for PEAR and its modules, which we include in the distribution. 22 // Updated for the correct location in the nix store. 23 set_include_path('${cfg.package}/WEB-INF/lib/pear' . PATH_SEPARATOR . get_include_path()); 24 define('DSN', 'mysqli://${cfg.database.user}@${cfg.database.host}/${cfg.database.name}?charset=utf8mb4'); 25 define('MULTIORG_MODE', ${lib.boolToString cfg.settings.multiorgMode}); 26 define('EMAIL_REQUIRED', ${lib.boolToString cfg.settings.emailRequired}); 27 define('WEEKEND_START_DAY', ${toString cfg.settings.weekendStartDay}); 28 define('FORUM_LINK', '${cfg.settings.forumLink}'); 29 define('HELP_LINK', '${cfg.settings.helpLink}'); 30 define('SENDER', '${cfg.settings.email.sender}'); 31 define('MAIL_MODE', '${cfg.settings.email.mode}'); 32 define('MAIL_SMTP_HOST', '${toString cfg.settings.email.smtpHost}'); 33 define('MAIL_SMTP_PORT', '${toString cfg.settings.email.smtpPort}'); 34 define('MAIL_SMTP_USER', '${cfg.settings.email.smtpUser}'); 35 define('MAIL_SMTP_PASSWORD', ${smtpPassword}); 36 define('MAIL_SMTP_AUTH', ${lib.boolToString cfg.settings.email.smtpAuth}); 37 define('MAIL_SMTP_DEBUG', ${lib.boolToString cfg.settings.email.smtpDebug}); 38 define('DEFAULT_CSS', 'default.css'); 39 define('RTL_CSS', 'rtl.css'); // For right to left languages. 40 define('LANG_DEFAULT', '${cfg.settings.defaultLanguage}'); 41 define('CURRENCY_DEFAULT', '${cfg.settings.defaultCurrency}'); 42 define('EXPORT_DECIMAL_DURATION', ${lib.boolToString cfg.settings.exportDecimalDuration}); 43 define('REPORT_FOOTER', ${lib.boolToString cfg.settings.reportFooter}); 44 define('AUTH_MODULE', 'db'); 45 ''; 46 package = pkgs.stdenv.mkDerivation rec { 47 pname = "anuko-time-tracker"; 48 inherit (src) version; 49 src = cfg.package; 50 installPhase = '' 51 mkdir -p $out 52 cp -r * $out/ 53 54 # Link config file 55 ln -s ${configFile} $out/WEB-INF/config.php 56 57 # Link writable templates_c directory 58 rm -rf $out/WEB-INF/templates_c 59 ln -s ${cfg.dataDir}/templates_c $out/WEB-INF/templates_c 60 61 # Remove unsafe dbinstall.php 62 rm -f $out/dbinstall.php 63 ''; 64 }; 65in 66{ 67 options.services.anuko-time-tracker = { 68 enable = lib.mkEnableOption "Anuko Time Tracker"; 69 70 package = lib.mkPackageOption pkgs "anuko-time-tracker" { }; 71 72 database = { 73 createLocally = lib.mkOption { 74 type = lib.types.bool; 75 default = true; 76 description = "Create the database and database user locally."; 77 }; 78 79 host = lib.mkOption { 80 type = lib.types.str; 81 description = "Database host."; 82 default = "localhost"; 83 }; 84 85 name = lib.mkOption { 86 type = lib.types.str; 87 description = "Database name."; 88 default = "anuko_time_tracker"; 89 }; 90 91 user = lib.mkOption { 92 type = lib.types.str; 93 description = "Database username."; 94 default = "anuko_time_tracker"; 95 }; 96 97 passwordFile = lib.mkOption { 98 type = lib.types.nullOr lib.types.str; 99 description = "Database user password file."; 100 default = null; 101 }; 102 }; 103 104 poolConfig = lib.mkOption { 105 type = lib.types.attrsOf ( 106 lib.types.oneOf [ 107 lib.types.str 108 lib.types.int 109 lib.types.bool 110 ] 111 ); 112 default = { 113 "pm" = "dynamic"; 114 "pm.max_children" = 32; 115 "pm.start_servers" = 2; 116 "pm.min_spare_servers" = 2; 117 "pm.max_spare_servers" = 4; 118 "pm.max_requests" = 500; 119 }; 120 description = '' 121 Options for Anuko Time Tracker's PHP-FPM pool. 122 ''; 123 }; 124 125 hostname = lib.mkOption { 126 type = lib.types.str; 127 default = 128 if config.networking.domain != null then config.networking.fqdn else config.networking.hostName; 129 defaultText = lib.literalExpression "config.networking.fqdn"; 130 example = "anuko.example.com"; 131 description = '' 132 The hostname to serve Anuko Time Tracker on. 133 ''; 134 }; 135 136 nginx = lib.mkOption { 137 type = lib.types.submodule ( 138 lib.recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) { } 139 ); 140 default = { }; 141 example = lib.literalExpression '' 142 { 143 serverAliases = [ 144 "anuko.''${config.networking.domain}" 145 ]; 146 147 # To enable encryption and let let's encrypt take care of certificate 148 forceSSL = true; 149 enableACME = true; 150 } 151 ''; 152 description = '' 153 With this option, you can customize the Nginx virtualHost settings. 154 ''; 155 }; 156 157 dataDir = lib.mkOption { 158 type = lib.types.str; 159 default = "/var/lib/anuko-time-tracker"; 160 description = "Default data folder for Anuko Time Tracker."; 161 example = "/mnt/anuko-time-tracker"; 162 }; 163 164 user = lib.mkOption { 165 type = lib.types.str; 166 default = "anuko_time_tracker"; 167 description = "User under which Anuko Time Tracker runs."; 168 }; 169 170 settings = { 171 multiorgMode = lib.mkOption { 172 type = lib.types.bool; 173 default = true; 174 description = '' 175 Defines whether users see the Register option in the menu of Time Tracker that allows them 176 to self-register and create new organizations (top groups). 177 ''; 178 }; 179 180 emailRequired = lib.mkOption { 181 type = lib.types.bool; 182 default = false; 183 description = "Defines whether an email is required for new registrations."; 184 }; 185 186 weekendStartDay = lib.mkOption { 187 type = lib.types.int; 188 default = 6; 189 description = '' 190 This option defines which days are highlighted with weekend color. 191 6 means Saturday. For Saudi Arabia, etc. set it to 4 for Thursday and Friday to be 192 weekend days. 193 ''; 194 }; 195 196 forumLink = lib.mkOption { 197 type = lib.types.str; 198 description = "Forum link from the main menu."; 199 default = "https://www.anuko.com/forum/viewforum.php?f=4"; 200 }; 201 202 helpLink = lib.mkOption { 203 type = lib.types.str; 204 description = "Help link from the main menu."; 205 default = "https://www.anuko.com/time-tracker/user-guide/index.htm"; 206 }; 207 208 email = { 209 sender = lib.mkOption { 210 type = lib.types.str; 211 description = "Default sender for mail."; 212 default = "Anuko Time Tracker <bounces@example.com>"; 213 }; 214 215 mode = lib.mkOption { 216 type = lib.types.str; 217 description = "Mail sending mode. Can be 'mail' or 'smtp'."; 218 default = "smtp"; 219 }; 220 221 smtpHost = lib.mkOption { 222 type = lib.types.str; 223 description = "MTA hostname."; 224 default = "localhost"; 225 }; 226 227 smtpPort = lib.mkOption { 228 type = lib.types.int; 229 description = "MTA port."; 230 default = 25; 231 }; 232 233 smtpUser = lib.mkOption { 234 type = lib.types.str; 235 description = "MTA authentication username."; 236 default = ""; 237 }; 238 239 smtpAuth = lib.mkOption { 240 type = lib.types.bool; 241 default = false; 242 description = "MTA requires authentication."; 243 }; 244 245 smtpPasswordFile = lib.mkOption { 246 type = lib.types.nullOr lib.types.path; 247 default = null; 248 example = "/var/lib/anuko-time-tracker/secrets/smtp-password"; 249 description = '' 250 Path to file containing the MTA authentication password. 251 ''; 252 }; 253 254 smtpDebug = lib.mkOption { 255 type = lib.types.bool; 256 default = false; 257 description = "Debug mail sending."; 258 }; 259 }; 260 261 defaultLanguage = lib.mkOption { 262 type = lib.types.str; 263 description = '' 264 Defines Anuko Time Tracker default language. It is used on Time Tracker login page. 265 After login, a language set for user group is used. 266 Empty string means the language is defined by user browser. 267 ''; 268 default = ""; 269 example = "nl"; 270 }; 271 272 defaultCurrency = lib.mkOption { 273 type = lib.types.str; 274 description = '' 275 Defines a default currency symbol for new groups. 276 Use , £, a more specific dollar like US$, CAD, etc. 277 ''; 278 default = "$"; 279 example = ""; 280 }; 281 282 exportDecimalDuration = lib.mkOption { 283 type = lib.types.bool; 284 default = true; 285 description = '' 286 Defines whether time duration values are decimal in CSV and XML data 287 exports (1.25 vs 1:15). 288 ''; 289 }; 290 291 reportFooter = lib.mkOption { 292 type = lib.types.bool; 293 default = true; 294 description = "Defines whether to use a footer on reports."; 295 }; 296 }; 297 }; 298 299 config = lib.mkIf cfg.enable { 300 301 assertions = [ 302 { 303 assertion = cfg.database.createLocally -> cfg.database.passwordFile == null; 304 message = '' 305 <option>services.anuko-time-tracker.database.passwordFile</option> cannot be specified if 306 <option>services.anuko-time-tracker.database.createLocally</option> is set to true. 307 ''; 308 } 309 { 310 assertion = cfg.settings.email.smtpAuth -> (cfg.settings.email.smtpPasswordFile != null); 311 message = '' 312 <option>services.anuko-time-tracker.settings.email.smtpPasswordFile</option> needs to be set if 313 <option>services.anuko-time-tracker.settings.email.smtpAuth</option> is enabled. 314 ''; 315 } 316 ]; 317 318 services.phpfpm = { 319 pools.anuko-time-tracker = { 320 inherit (cfg) user; 321 group = config.services.nginx.group; 322 settings = { 323 "listen.owner" = config.services.nginx.user; 324 "listen.group" = config.services.nginx.group; 325 } // cfg.poolConfig; 326 }; 327 }; 328 329 services.nginx = { 330 enable = lib.mkDefault true; 331 recommendedTlsSettings = true; 332 recommendedOptimisation = true; 333 recommendedGzipSettings = true; 334 virtualHosts."${cfg.hostname}" = lib.mkMerge [ 335 cfg.nginx 336 { 337 root = lib.mkForce "${package}"; 338 locations = { 339 "/".index = "index.php"; 340 "~ [^/]\\.php(/|$)" = { 341 extraConfig = '' 342 fastcgi_split_path_info ^(.+?\.php)(/.*)$; 343 fastcgi_pass unix:${config.services.phpfpm.pools.anuko-time-tracker.socket}; 344 ''; 345 }; 346 }; 347 } 348 ]; 349 }; 350 351 services.mysql = lib.mkIf cfg.database.createLocally { 352 enable = lib.mkDefault true; 353 package = lib.mkDefault pkgs.mariadb; 354 ensureDatabases = [ cfg.database.name ]; 355 ensureUsers = [ 356 { 357 name = cfg.database.user; 358 ensurePermissions = { 359 "${cfg.database.name}.*" = "ALL PRIVILEGES"; 360 }; 361 } 362 ]; 363 }; 364 365 systemd = { 366 services = { 367 anuko-time-tracker-setup-database = lib.mkIf cfg.database.createLocally { 368 description = "Set up Anuko Time Tracker database"; 369 serviceConfig = { 370 Type = "oneshot"; 371 RemainAfterExit = true; 372 }; 373 wantedBy = [ "phpfpm-anuko-time-tracker.service" ]; 374 after = [ "mysql.service" ]; 375 script = 376 let 377 mysql = "${config.services.mysql.package}/bin/mysql"; 378 in 379 '' 380 if [ ! -f ${cfg.dataDir}/.dbexists ]; then 381 # Load database schema provided with package 382 ${mysql} ${cfg.database.name} < ${cfg.package}/mysql.sql 383 384 touch ${cfg.dataDir}/.dbexists 385 fi 386 ''; 387 }; 388 }; 389 tmpfiles.rules = [ 390 "d ${cfg.dataDir} 0750 ${cfg.user} ${config.services.nginx.group} -" 391 "d ${cfg.dataDir}/templates_c 0750 ${cfg.user} ${config.services.nginx.group} -" 392 ]; 393 }; 394 395 users.users."${cfg.user}" = { 396 isSystemUser = true; 397 group = config.services.nginx.group; 398 }; 399 }; 400 401 meta.maintainers = with lib.maintainers; [ michaelshmitty ]; 402}