defmodule Patreon.API.V2.Resource.User do require Logger @typedoc """ Represents a Patreon user. * `:about` - The user's about text, which appears on their profile. * `:can_see_nsfw` - `true` if this user can view nsfw content. * `:created` - Datetime of this user's account creation. * `:email` - The user's email address. Requires certain scopes to access. See the scopes section of the patreon API documentaiton. * `:first_name` - The users first name. * `:full_name` - The users full name. * `:hide_pledges` - `true` if the user has chosen to keep private which creators they pledge to. * `:image_url` - The user's profile picture URL, scaled to width 400px. * `:is_email_verified` - `true` if the user has confirmed their email. * `:last_name` - The users last name. * `:like_count` - How many posts the user has liked. * `:social_connections` - Mapping from user's connected app names to external user id on the respective app. * `:thumb_url` - The user's profile picture URL, scaled to a square of size 100x100px. * `:url` - URL of this user's creator or patron profile. * `:vanity` - The public "username" of the user. """ @type t :: %__MODULE__{ id: String.t, about: String.t | nil, can_see_nsfw: boolean | nil, created: DateTime.t | nil, email: String.t | nil, first_name: String.t | nil, full_name: String.t | nil, hide_pledges: boolean | nil, image_url: String.t | nil, is_email_verified: boolean | nil, last_name: String.t | nil, like_count: integer | nil, social_connections: Patreon.API.V2.Resource.SocialConnections.t | nil, thumb_url: String.t | nil, url: String.t | nil, vanity: String.t | nil, included: %{campaign: Patreon.API.V2.Resource.Campaign.t | nil, memberships: any | []} } defstruct [ :id, :about, :can_see_nsfw, :created, :email, :first_name, :full_name, :hide_pledges, :image_url, :is_email_verified, :last_name, :like_count, :social_connections, :thumb_url, :url, :vanity, :included, ] @spec from_response(%{data: map, included: list(map)}) :: %__MODULE__{} def from_response(%{data: data, included: includes}) do user = %{id: data.id} |> Map.merge(data.attributes) |> Map.put_new(:included, %{campaign: nil, memberships: []}) |> add_includes(includes) Kernel.struct(__MODULE__, user) end @spec from_response(%{data: map}) :: %__MODULE__{} def from_response(%{data: data}) do from_response(%{data: data, included: []}) end def add_includes(user, includes) do %{user | included: Enum.reduce(includes, user.included, &struct_from_include/2)} end def struct_from_include(%{type: "campaign"} = include, %{campaign: nil, memberships: _memberships} = user_includes) do %{user_includes | campaign: Patreon.API.V2.Resource.Campaign.from_response(include)} end def struct_from_include(%{type: "campaign"} = _include, %{campaign: _existing_campaign, memberships: _memberships} = user_includes) do Logger.warn "User already contained an existing campaign." user_includes end def struct_from_include(%{type: "member"} = include, %{campaign: _campaign, memberships: memberships} = user_includes) do %{user_includes | memberships: [Patreon.API.V2.Resource.Member.from_response(include) | memberships]} end def opts_to_query([]) do [] end def opts_to_query(include_fields) do Enum.reduce(include_fields, ["fields[user]": "", include: "", "fields[campaign]": "", "fields[member]": ""], &generate_query_option/2) |> Keyword.filter(fn({_key, val}) -> val != "" end) end defp generate_query_option({:user, []}, acc) do acc end defp generate_query_option({:user, user_fields}, acc) do Keyword.put(acc, :"fields[user]", Enum.join(user_fields, ",")) end defp generate_query_option({:campaign, campaign_fields}, acc) do updated_include = [Keyword.get(acc, :include), "campaign"] |> Enum.filter(fn(val) -> val != "" end) |> Enum.join(",") Keyword.put(acc, :"fields[campaign]", Enum.join(campaign_fields, ",")) |> Keyword.put(:include, updated_include) end defp generate_query_option({:memberships, memberships_fields}, acc) do updated_include = [Keyword.get(acc, :include), "memberships"] |> Enum.filter(fn(val) -> val != "" end) |> Enum.join(",") Keyword.put(acc, :"fields[memberships]", Enum.join(memberships_fields, ",")) |> Keyword.put(:include, updated_include) end end