args@{ lib, pkgs, config, machine, ... }: with lib; let cfg = config.custom.users; inherit (machine) home-only; inherit (machine) stateVersion; valid-on-machine = on: # TODO: iterate over possibilities ( if machine.type == "server" then on.server else if machine.type == "pc" then on.pc else false ); users = lib.filterAttrs (_: value: valid-on-machine value.on) cfg; home-users = lib.filterAttrs (_: value: value.apply-home-configs) users; programs = lib.attrsets.attrValues config.custom.program; in { options = let userType = types.submodule { options = { name = mkOption { type = types.str; default = [ ]; }; groups = mkOption { type = types.listOf types.str; default = [ ]; }; keys = mkOption { type = types.listOf types.str; default = [ ]; }; shell = mkOption { type = types.package; default = pkgs.fish; }; on = mkOption { type = types.submodule { options = { server = mkOption { type = types.bool; default = true; }; pc = mkOption { type = types.bool; default = false; }; }; }; default = { }; }; apply-home-configs = mkOption { type = types.bool; default = false; }; }; }; in { custom.users = mkOption { type = types.attrsOf userType; }; }; config = lib.mkMerge [ ( if (!builtins.isNull home-only) then lib.mkMerge ([ { home = { inherit stateVersion; username = toString home-only; homeDirectory = "/home/${toString home-only}"; }; } ] # ++ map (program: program.home-config) programs ) else (lib.mkMerge ([ { users.extraUsers = lib.mapAttrs (name: value: { isNormalUser = true; extraGroups = value.groups; openssh.authorizedKeys.keys = value.keys; inherit (value) shell; description = name; }) users; home-manager.users = lib.mapAttrs ( name: value: (_: { imports = ( [ ] ++ (map (program: program.home-config) programs) ); home = { inherit stateVersion; username = name; homeDirectory = "/home/${name}"; }; }) ) home-users; } ])) ) ]; }