Current section
Files
Jump to
Current section
Files
lib/exldap/update.ex
defmodule Exldap.Update do
@moduledoc """
A module for adding / updating information in LDAP from Elixir via Exldap
"""
@type distinguished_name :: String.t()
@type modify_op :: term()
@type mod_op_name :: :add | :delete | :replace
@type return_value :: :ok | {:ok, {:referral, [String.t()]}} | {:error, term()}
@doc """
Add an entry. The entry must not exist. Attributes can be supplied
either as a map or a keyword list, with either atoms or strings as keys.
## Examples:
iex> Exldap.Update.add(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> %{objectClass: ["person", "top"], sn: "User", cn: "someUser"}
...> )
:ok
iex> Exldap.Update.add(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> [{"objectClass", "top"}, objectClass: "person", sn: "User", cn: "someUser"]
...> )
:ok
"""
@spec add(pid(), distinguished_name(), map() | list(keyword())) :: return_value()
def add(connection, dn, attrs) do
:eldap.add(connection, force_charlist(dn), convert_attributes(attrs))
end
@doc """
Delete an entry.
## Example:
iex> Exldap.Update.delete(connection, "CN=someUser,OU=Accounts,DC=example,DC=com")
:ok
iex> Exldap.Update.delete(connection, "CN=someUser,OU=Accounts,DC=example,DC=com")
{:error, :noSuchObject}
"""
@spec delete(pid(), distinguished_name()) :: return_value()
def delete(connection, dn) do
:eldap.delete(connection, force_charlist(dn))
end
@spec mod_add(term(), term() | list(term())) :: modify_op()
def mod_add(type, values) do
with {k, v} <- convert_attribute_value({type, values}) do
:eldap.mod_add(k, v)
end
end
@spec mod_delete(term(), term() | list(term())) :: modify_op()
def mod_delete(type, values) do
with {k, v} <- convert_attribute_value({type, values}) do
:eldap.mod_delete(k, v)
end
end
@spec mod_replace(term(), term() | list(term())) :: modify_op()
def mod_replace(type, values) do
with {k, v} <- convert_attribute_value({type, values}) do
:eldap.mod_replace(k, v)
end
end
@doc """
Modify an entry.
## Examples:
# Single modification
iex> Exldap.Update.modify(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> Exldap.Update.mod_add("displayName", "Some User")
...> )
:ok
# Multiple modifications
iex> Exldap.Update.modify(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> [
...> Exldap.Update.mod_add("mail", ["someuser@example.com", "some.user@example.com"]),
...> Exldap.Update.mod_delete("displayName", "Some User")
...> ]
...> )
:ok
# Flat form
iex> Exldap.Update.modify(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> {:add, :displayName, "Some User"}
...> )
:ok
iex> Exldap.Update.modify(
...> connection,
...> "CN=someUser,OU=Accounts,DC=example,DC=com",
...> [
...> {:add, :mail, ["someuser@example.com", "some.user@example.com"]},
...> {:delete, :displayName, "Some User"}
...> ]
...> )
:ok
"""
@spec modify(pid(), distinguished_name(), modify_op() | list(modify_op())) :: return_value()
def modify(connection, dn, ops) when is_list(ops) do
ops =
ops
|> Enum.map(fn op ->
case op do
{:add, _, _} -> convert_op_spec(op)
{:delete, _, _} -> convert_op_spec(op)
{:replace, _, _} -> convert_op_spec(op)
_ -> op
end
end)
:eldap.modify(connection, force_charlist(dn), ops)
end
def modify(connection, dn, op), do: modify(connection, dn, [op])
defp convert_op_spec({op, type, values}) do
apply(__MODULE__, String.to_atom("mod_#{op}"), [type, values])
end
defp convert_attribute_value({key, val}) when is_list(val) do
{
key |> force_charlist(),
val |> Enum.map(&force_charlist/1)
}
end
defp convert_attribute_value({key, val}), do: convert_attribute_value({key, [val]})
defp convert_attributes(attrs) do
attrs
|> flat_attribute_list()
|> Enum.map(&convert_attribute_value/1)
end
defp flat_attribute_list(attrs) do
attrs
|> Enum.reduce([], fn {key, val}, acc ->
key =
cond do
is_atom(key) -> key
is_binary(key) -> String.to_atom(key)
true -> String.to_atom(to_string(key))
end
val = if is_list(val), do: val, else: [val]
acc |> Keyword.update(key, val, fn v -> v ++ val end)
end)
end
defp force_charlist(v), do: v |> to_string() |> to_charlist()
end