diff --git a/flake.lock b/flake.lock index 339242d..4f0959c 100644 --- a/flake.lock +++ b/flake.lock @@ -608,11 +608,11 @@ "nixpkgs-lib": "nixpkgs-lib_2" }, "locked": { - "lastModified": 1786138155, - "narHash": "sha256-bfG5UfaAs2AtgjdJ3CwaRGC/wbpBEdA42UIoIu94uFw=", + "lastModified": 1786139928, + "narHash": "sha256-5r1U9l7mY8HiXhubW4M2pFmlN6c/O94Mkf26KRJXDqc=", "owner": "nixcafe", "repo": "purr", - "rev": "9e9deee2613860f77f9d1e47f53ad303be24579c", + "rev": "48d591b9906059f84efd90685ddf670cdd269487", "type": "github" }, "original": { diff --git a/modules/home/nixos/apps/thunderbird/default.nix b/modules/home/nixos/apps/thunderbird/default.nix index ab15e87..b2a53a9 100644 --- a/modules/home/nixos/apps/thunderbird/default.nix +++ b/modules/home/nixos/apps/thunderbird/default.nix @@ -120,13 +120,27 @@ in }; }; - accounts.calendar.accounts = lib.mkIf (user.addToAccounts && user.calendar != null) { - ${user.name}.thunderbird.enable = true; - }; + accounts.calendar.accounts = lib.mkIf (user.addToAccounts && user.calendar != [ ]) ( + lib.listToAttrs ( + map (account: { + inherit (account) name; + value = { + thunderbird.enable = true; + }; + }) user.calendar + ) + ); - accounts.contact.accounts = lib.mkIf (user.addToAccounts && user.contact != null) { - ${user.name}.thunderbird.enable = true; - }; + accounts.contact.accounts = lib.mkIf (user.addToAccounts && user.contact != [ ]) ( + lib.listToAttrs ( + map (account: { + inherit (account) name; + value = { + thunderbird.enable = true; + }; + }) user.contact + ) + ); ${namespace}.system.impermanence = lib.mkIf cfg.persistence { directories = [ diff --git a/modules/home/user/default.nix b/modules/home/user/default.nix index a8edbab..521cc4b 100644 --- a/modules/home/user/default.nix +++ b/modules/home/user/default.nix @@ -14,9 +14,10 @@ let mkOption types optionalAttrs + listToAttrs ; - name = cfg.settings.name or "nixos"; + inherit (cfg) name; home = if isLinux then "/home/${name}" else "/Users/${name}"; cfg = config.${namespace}.user; @@ -108,182 +109,217 @@ in }; }; calendar = mkOption { - type = nullOr (submodule { - options = { - primary = mkOption { - type = bool; - default = true; - description = '' - Whether this is the primary calendar account. - ''; - }; - primaryCollection = mkOption { - type = nullOr str; - default = null; - description = '' - The primary collection of the account. Required when the - account has multiple collections. - ''; - }; - local = mkOption { - type = submodule { - options = { - path = mkOption { - type = str; - default = "${home}/.calendar/${name}"; - description = "The path of the storage."; - }; - type = mkOption { - type = enum [ - "filesystem" - "singlefile" - ]; - default = "filesystem"; - description = "The type of the storage."; - }; - fileExt = mkOption { - type = nullOr str; - default = ".ics"; - description = "The file extension to use."; - }; - encoding = mkOption { - type = nullOr str; - default = null; - description = '' - File encoding for items, both content and file name. - ''; - }; + type = listOf ( + submodule ( + { config, ... }: + let + accountName = config.name; + in + { + options = { + name = mkOption { + type = str; + default = "${name}-calendar"; + description = '' + The name of the calendar account, used as the account + identifier and displayed name. + ''; }; - }; - default = { }; - description = "Local configuration for the calendar."; - }; - remote = mkOption { - type = nullOr (submodule { - options = { - type = mkOption { - type = enum [ - "caldav" - "http" - "google_calendar" - ]; - description = "The type of the storage."; - }; - url = mkOption { - type = nullOr str; - default = null; - description = "The URL of the storage."; - }; - userName = mkOption { - type = nullOr str; - default = cfg.email.userName; - description = "User name for authentication."; - }; - passwordCommand = mkOption { - type = nullOr (listOf str); - default = null; - example = [ - "pass" - "caldav" - ]; - description = '' - A command that prints the password to standard output. - ''; + primary = mkOption { + type = bool; + default = false; + description = '' + Whether this is the primary calendar account. At most + one account may be primary. + ''; + }; + primaryCollection = mkOption { + type = nullOr str; + default = null; + description = '' + The primary collection of the account. Required when the + account has multiple collections. + ''; + }; + local = mkOption { + type = submodule { + options = { + path = mkOption { + type = str; + default = "${home}/.calendar/${accountName}"; + description = "The path of the storage."; + }; + type = mkOption { + type = enum [ + "filesystem" + "singlefile" + ]; + default = "filesystem"; + description = "The type of the storage."; + }; + fileExt = mkOption { + type = nullOr str; + default = ".ics"; + description = "The file extension to use."; + }; + encoding = mkOption { + type = nullOr str; + default = null; + description = '' + File encoding for items, both content and file name. + ''; + }; + }; }; + default = { }; + description = "Local configuration for the calendar."; }; - }); - default = null; - description = "Remote configuration for the calendar."; - }; - }; - }); - default = cfg.settings.calendar or null; + remote = mkOption { + type = nullOr (submodule { + options = { + type = mkOption { + type = enum [ + "caldav" + "http" + "google_calendar" + ]; + description = "The type of the storage."; + }; + url = mkOption { + type = nullOr str; + default = null; + description = "The URL of the storage."; + }; + userName = mkOption { + type = nullOr str; + default = name; + description = "User name for authentication."; + }; + passwordCommand = mkOption { + type = nullOr (listOf str); + default = null; + example = [ + "pass" + "caldav" + ]; + description = '' + A command that prints the password to standard output. + ''; + }; + }; + }); + default = null; + description = "Remote configuration for the calendar."; + }; + }; + } + ) + ); + default = cfg.settings.calendar or [ ]; description = '' - The calendar account of the user. When set and - `cattery.user.addToAccounts` is enabled, this is injected into - `accounts.calendar.accounts`.${name}. + A list of calendar accounts. Each account is injected into + `accounts.calendar.accounts.` when + `cattery.user.addToAccounts` is enabled. The account name + defaults to `-calendar` and can be overridden. ''; }; contact = mkOption { - type = nullOr (submodule { - options = { - local = mkOption { - type = submodule { - options = { - path = mkOption { - type = str; - default = "${home}/.contacts/${name}"; - description = "The path of the storage."; - }; - type = mkOption { - type = enum [ - "filesystem" - "singlefile" - ]; - default = "filesystem"; - description = "The type of the storage."; - }; - fileExt = mkOption { - type = nullOr str; - default = ".vcf"; - description = "The file extension to use."; - }; - encoding = mkOption { - type = nullOr str; - default = null; - description = '' - File encoding for items, both content and file name. - ''; - }; + type = listOf ( + submodule ( + { config, ... }: + let + accountName = config.name; + in + { + options = { + name = mkOption { + type = str; + default = "${name}-contact"; + description = '' + The name of the contact account, used as the account + identifier and displayed name. + ''; }; - }; - default = { }; - description = "Local configuration for the contacts."; - }; - remote = mkOption { - type = nullOr (submodule { - options = { - type = mkOption { - type = enum [ - "carddav" - "http" - "google_contacts" - ]; - description = "The type of the storage."; - }; - url = mkOption { - type = nullOr str; - default = null; - description = "The URL of the storage."; - }; - userName = mkOption { - type = nullOr str; - default = cfg.email.userName; - description = "User name for authentication."; - }; - passwordCommand = mkOption { - type = nullOr (listOf str); - default = null; - example = [ - "pass" - "carddav" - ]; - description = '' - A command that prints the password to standard output. - ''; + local = mkOption { + type = submodule { + options = { + path = mkOption { + type = str; + default = "${home}/.contacts/${accountName}"; + description = "The path of the storage."; + }; + type = mkOption { + type = enum [ + "filesystem" + "singlefile" + ]; + default = "filesystem"; + description = "The type of the storage."; + }; + fileExt = mkOption { + type = nullOr str; + default = ".vcf"; + description = "The file extension to use."; + }; + encoding = mkOption { + type = nullOr str; + default = null; + description = '' + File encoding for items, both content and file name. + ''; + }; + }; }; + default = { }; + description = "Local configuration for the contacts."; }; - }); - default = null; - description = "Remote configuration for the contacts."; - }; - }; - }); - default = cfg.settings.contact or null; + remote = mkOption { + type = nullOr (submodule { + options = { + type = mkOption { + type = enum [ + "carddav" + "http" + "google_contacts" + ]; + description = "The type of the storage."; + }; + url = mkOption { + type = nullOr str; + default = null; + description = "The URL of the storage."; + }; + userName = mkOption { + type = nullOr str; + default = name; + description = "User name for authentication."; + }; + passwordCommand = mkOption { + type = nullOr (listOf str); + default = null; + example = [ + "pass" + "carddav" + ]; + description = '' + A command that prints the password to standard output. + ''; + }; + }; + }); + default = null; + description = "Remote configuration for the contacts."; + }; + }; + } + ) + ); + default = cfg.settings.contact or [ ]; description = '' - The contacts account of the user. When set and - `cattery.user.addToAccounts` is enabled, this is injected into - `accounts.contact.accounts`.${name}. + A list of contact accounts. Each account is injected into + `accounts.contact.accounts.` when + `cattery.user.addToAccounts` is enabled. The account name + defaults to `-contact` and can be overridden. ''; }; home = mkOption { @@ -364,21 +400,31 @@ in }; } - (mkIf (cfg.addToAccounts && cfg.calendar != null) { - accounts.calendar.accounts.${name} = { - inherit (cfg.calendar) - primary - primaryCollection - local - remote - ; - }; + (mkIf (cfg.addToAccounts && cfg.calendar != [ ]) { + accounts.calendar.accounts = listToAttrs ( + map (account: { + inherit (account) name; + value = { + inherit (account) + primary + primaryCollection + local + remote + ; + }; + }) cfg.calendar + ); }) - (mkIf (cfg.addToAccounts && cfg.contact != null) { - accounts.contact.accounts.${name} = { - inherit (cfg.contact) local remote; - }; + (mkIf (cfg.addToAccounts && cfg.contact != [ ]) { + accounts.contact.accounts = listToAttrs ( + map (account: { + inherit (account) name; + value = { + inherit (account) local remote; + }; + }) cfg.contact + ); }) ]; }