{ config, lib, inputs, ... }: let inherit (inputs.self.lib.lib) unmerged mkAlmostOptionDefault; inherit (lib.options) mkOption mkEnableOption; inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.attrsets) filterAttrs mapAttrsToList nameValuePair; inherit (lib.lists) optional toList; inherit (lib.strings) toLower removeSuffix concatMapStrings concatStringsSep optionalString; ldap'lib = { specialArgs = { nixosConfig = config; ldap = config.users.ldap // { lib = config.lib.ldap; }; }; objectModule = ldapObjectModule; objectType = lib.types.submoduleWith { modules = [ ldapObjectModule ]; inherit (ldap'lib) specialArgs; }; objectSettingType' = lib.types.submoduleWith { modules = [ ldapObjectSettingModule ]; inherit (ldap'lib) specialArgs; }; objectSettingType = let mapToObjectSetting = value: { inherit value; }; in lib.types.coercedTo ldapValueType mapToObjectSetting ldap'lib.objectSettingType'; objectSettingsModule = ldapObjectSettingsModule; objectSettingsType = lib.types.submoduleWith { modules = [ ldapObjectSettingsModule ]; inherit (ldap'lib) specialArgs; }; mapObjectSettingsToPair = settings: nameValuePair (removeSuffix ",${config.users.ldap.base}" settings.dn) (unmerged.mergeAttrs settings.settings); mapObjectSettingsToAttr = settings: let pair = ldap'lib.mapObjectSettingsToPair settings; in { ${pair.name} = pair.value; }; mkLdapModifyObjectSettingValues = let mkLdapModifyValues = setting: concatMapStrings (value: '' ${setting.key}: ${toString value} '') (toList setting.value); in mkLdapModifyValues; mkLdapModifyObjectSettings = let mkLdapModifySetting = setting: '' ${setting.modifyType}: ${setting.key} '' + ldap'lib.mkLdapModifyObjectSettingValues setting; in settings: mapAttrsToList (_: mkLdapModifySetting) settings; mkLdapAddObjectSettings = settings: mapAttrsToList (_: ldap'lib.mkLdapModifyObjectSettingValues) settings; mkLdapModifyObject = let mkHeader = changeType: object: '' dn: ${object.dn} changetype: ${changeType} ''; in { modify = object: let enabledSettings' = filterAttrs (_: setting: setting.enable) object.settings; enabledSettings = ldap'lib.mkLdapModifyObjectSettings enabledSettings'; replaceSettings' = filterAttrs (_: setting: setting.modifyType == "replace") enabledSettings'; replaceSettings = ldap'lib.mkLdapModifyObjectSettings replaceSettings'; addSettings' = filterAttrs (_: setting: setting.modifyType == "add") enabledSettings'; replaceText = mkHeader "modify" object + concatStringsSep "-\n" replaceSettings; text = mkHeader "modify" object + concatStringsSep "-\n" enabledSettings; in concatStringsSep "-\n\n" ( [ text ] ++ optional (addSettings' != { }) replaceText ); add = object: let enabledSettings = filterAttrs (_: setting: setting.enable) object.settings; addSettings = ldap'lib.mkLdapAddObjectSettings enabledSettings; in mkHeader "add" object + concatStringsSep "-\n" addSettings; delete = object: mkHeader "delete" object; modrdn = object: { newrdn, deleteoldrdn, newsuperior }: let modifySettings = '' newrdn: ${newrdn} deleteoldrdn: ${if deleteoldrdn == true then "1" else if deleteoldrdn == "false" then "0" else toString deleteoldrdn} '' + optionalString (newsuperior != null) '' newsuperior: ${newsuperior} ''; in mkHeader "modrdn" + modifySettings; moddn = object: { deleteoldrdn, newsuperior }: let modifySettings = '' deleteoldrdn: ${if deleteoldrdn == true then "1" else if deleteoldrdn == "false" then "0" else toString deleteoldrdn} newsuperior: ${newsuperior} ''; in mkHeader "moddn" + modifySettings; }; }; ldapPrimitiveType = with lib.types; oneOf [ str int ]; ldapValueType = with lib.types; oneOf [ ldapPrimitiveType (listOf ldapPrimitiveType) ]; ldapObjectSettingModule = {config, name, ...}: { options = with lib.types; { enable = mkEnableOption "setting" // { default = true; }; key = mkOption { type = str; default = name; }; value = mkOption { type = ldapValueType; }; modifyType = mkOption { type = enum [ "replace" "add" "delete" ]; default = if toLower config.key == "objectclass" then "add" else "replace"; }; }; }; ldapObjectSettingsModule = {config, ...}: { options = with lib.types; { enable = mkEnableOption "object" // { default = true; }; dn = mkOption { type = str; }; settings = mkOption { type = unmerged.types.attrs; }; }; config = { settings = { dn = mkAlmostOptionDefault config.dn; }; }; }; ldapObjectModule = {config, name, ldap, ...}: { options = with lib.types; { enable = mkEnableOption "object creation" // { default = true; }; dn = mkOption { type = str; default = "${name},${ldap.base}"; }; changeType = mkOption { type = enum [ "modify" "add" "delete" "modrdn" "moddn" ]; default = "modify"; }; changeText = mkOption { type = lines; }; objectClasses = mkOption { type = listOf str; default = [ ]; }; settings = mkOption { type = attrsOf ldap.lib.objectSettingType; default = { }; }; }; config = { settings = { objectClass = mkIf (config.objectClasses != [ ]) (mkOptionDefault config.objectClasses); }; changeText = mkOptionDefault (ldap'lib.mkLdapModifyObject.${config.changeType} config); }; }; in { options.users.ldap = with lib.types; { management.objects = mkOption { type = attrsOf ldap'lib.objectType; default = { }; }; }; config.lib.ldap = ldap'lib; }