defmodule Paddle.Attributes do @moduledoc ~S""" Module used internally by Paddle to manipulate / convert LDAP attributes. """ @spec get(Paddle.Class.t()) :: {:ok, map} | {:error, :missing_required_attributes, [atom]} @doc ~S""" Get the given and the generated attributes of a given class object. Examples: iex> Paddle.Attributes.get(%MyApp.PosixGroup{}) {:error, :missing_required_attributes, [:cn]} iex> Paddle.Attributes.get(%MyApp.PosixGroup{cn: "myGroup"}) {:ok, %{cn: "myGroup", description: nil, gidNumber: 4, memberUid: nil, objectClass: "posixGroup", userPassword: nil}} """ def get(class_object) do given_attributes = Map.from_struct(class_object) generated_attributes = generate_defaults(class_object) attributes = Map.merge(generated_attributes, given_attributes, &choose_value/3) required_attributes = Paddle.Class.required_attributes(class_object) missing_req_attributes = get_missing_req(attributes, required_attributes) case missing_req_attributes do [] -> {:ok, attributes} _ -> {:error, :missing_required_attributes, missing_req_attributes} end end defp generate_defaults(class_object) do for {attribute, func} <- Paddle.Class.generators(class_object), into: %{} do {attribute, func.(class_object)} end |> Map.merge(%{objectClass: Paddle.Class.object_classes(class_object)}) end defp choose_value(_key, generated_value, given_value) do case given_value do nil -> generated_value _ -> given_value end end defp get_missing_req(attributes, required_attributes) do attributes |> Enum.filter_map( fn {attribute, value} -> attribute in required_attributes and value == nil end, fn {attribute, _value} -> attribute end ) end end