Packages

phoenix_kit

2.54.2
2.64.0 2.63.0 2.62.2 2.62.1 2.62.0 2.61.0 2.60.3 2.60.2 2.60.1 2.60.0 2.59.0 2.58.0 2.57.1 2.57.0 2.56.1 2.56.0 2.55.1 2.55.0 2.54.2 2.54.1 2.54.0 2.53.0 2.52.2 2.52.1 2.52.0 2.51.0 2.50.0 2.49.1 2.49.0 2.48.0 2.47.0 2.46.0 2.45.0 2.44.0 2.43.1 2.43.0 2.42.1 2.42.0 2.41.6 2.41.4 2.41.3 2.41.2 2.41.1 2.41.0 2.40.1 2.40.0 2.39.0 2.38.1 2.38.0 2.37.5 2.37.4 2.37.3 2.37.2 2.37.1 2.37.0 2.36.1 2.36.0 2.35.0 2.34.0 2.33.0 2.32.1 2.32.0 2.31.1 2.31.0 2.30.0 2.29.1 2.29.0 2.28.2 2.28.1 2.28.0 2.27.2 2.27.1 2.27.0 2.26.1 2.26.0 2.25.0 2.24.0 2.23.3 2.23.2 2.23.1 2.23.0 2.22.24 2.22.23 2.22.22 2.22.21 2.22.20 2.22.19 2.22.18 2.22.17 2.22.16 2.22.15 2.22.14 2.22.13 2.22.12 2.22.11 2.22.10 2.22.9 2.22.8 2.22.7 2.22.6 2.22.5 2.22.4 2.22.3 2.22.2 2.22.1 2.22.0 2.21.5 2.21.4 2.21.3 2.21.2 2.21.1 2.21.0 2.20.0 2.19.0 2.18.1 2.18.0 2.17.0 2.16.0 2.15.1 2.15.0 2.14.2 2.14.1 2.14.0 2.13.19 2.13.18 2.13.17 2.13.16 2.13.15 2.13.13 2.13.12 2.13.11 2.13.10 2.13.9 2.13.8 2.13.7 2.13.6 2.13.5 2.13.4 2.13.3 2.13.2 2.13.1 2.13.0 2.12.1 2.12.0 2.11.0 2.10.0 2.9.0 2.8.1 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.0 2.0.1 2.0.0 1.7.236 1.7.235 1.7.234 1.7.233 1.7.232 1.7.231 1.7.230 1.7.229 1.7.228 1.7.227 1.7.226 1.7.225 1.7.224 1.7.223 1.7.222 1.7.221 1.7.220 1.7.219 1.7.218 1.7.217 1.7.216 1.7.215 1.7.214 1.7.213 1.7.212 1.7.211 1.7.210 1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules storage schemas folder.ex
Raw

lib/modules/storage/schemas/folder.ex

defmodule PhoenixKit.Modules.Storage.Folder do
  @moduledoc """
  Schema for media folders.

  Provides hierarchical organization for media files. Folders are purely
  metadata — storage buckets are unaware of folder structure.
  """

  use Ecto.Schema
  use PhoenixKit.SchemaPrefix
  import Ecto.Changeset

  @primary_key {:uuid, UUIDv7, autogenerate: true}
  @foreign_key_type UUIDv7

  @type t :: %__MODULE__{}

  @folder_colors ~w(default red orange amber yellow lime green emerald teal cyan sky blue violet purple fuchsia pink rose)

  schema "phoenix_kit_media_folders" do
    field :name, :string
    field :description, :string
    field :color, :string, default: "default"
    field :trashed_at, :utc_datetime
    # Folder hero-header customization. The cover (background) and logo (icon)
    # are media files living in the folder, excluded from its visible listing.
    # `header_size` is small/medium/large; the `header_show_*` flags toggle each
    # header element. New folders default to a small header (less vertical
    # space up front). Existing rows keep their stored size — the DB column
    # default (v134, "medium") only applies to raw inserts, which never happen
    # here; folders are always created via changeset, so this default wins.
    field :cover_file_uuid, UUIDv7
    field :logo_file_uuid, UUIDv7
    field :header_size, :string, default: "small"
    field :header_show_title, :boolean, default: true
    field :header_show_icon, :boolean, default: true
    field :header_show_creator, :boolean, default: true
    field :header_show_date, :boolean, default: true
    field :header_show_file_count, :boolean, default: true
    field :header_show_description, :boolean, default: true
    field :header_show_background, :boolean, default: true

    belongs_to :parent, __MODULE__,
      foreign_key: :parent_uuid,
      references: :uuid

    belongs_to :user, PhoenixKit.Users.Auth.User,
      foreign_key: :user_uuid,
      references: :uuid

    # The library the folder belongs to (V202; defaults to Media in the column).
    field :library_uuid, UUIDv7, read_after_writes: true

    belongs_to :library, PhoenixKit.Modules.Storage.Library,
      foreign_key: :library_uuid,
      references: :uuid,
      define_field: false

    has_many :children, __MODULE__,
      foreign_key: :parent_uuid,
      references: :uuid

    has_many :files, PhoenixKit.Modules.Storage.File,
      foreign_key: :folder_uuid,
      references: :uuid

    has_many :folder_links, PhoenixKit.Modules.Storage.FolderLink,
      foreign_key: :folder_uuid,
      references: :uuid

    timestamps(type: :utc_datetime)
  end

  def colors, do: @folder_colors

  def changeset(folder, attrs) do
    folder
    |> cast(attrs, [
      :name,
      :description,
      :parent_uuid,
      :user_uuid,
      :library_uuid,
      :color,
      :trashed_at,
      :cover_file_uuid,
      :logo_file_uuid,
      :header_size,
      :header_show_title,
      :header_show_icon,
      :header_show_creator,
      :header_show_date,
      :header_show_file_count,
      :header_show_description,
      :header_show_background
    ])
    |> validate_required([:name])
    |> validate_inclusion(:color, @folder_colors)
    |> validate_inclusion(:header_size, ~w(small medium large))
    |> validate_length(:name, min: 1, max: 255)
    |> validate_length(:description, max: 2000)
    |> validate_not_own_parent()
    |> foreign_key_constraint(:parent_uuid)
    |> foreign_key_constraint(:user_uuid)
    |> foreign_key_constraint(:library_uuid,
      name: :phoenix_kit_media_folders_library_uuid_fkey
    )
    |> unique_constraint([:name, :parent_uuid],
      name: :phoenix_kit_media_folders_name_parent_idx
    )
  end

  # A folder that is its own parent drops out of every listing, and a walk
  # of its subtree would never end.
  defp validate_not_own_parent(changeset) do
    uuid = get_field(changeset, :uuid)

    if uuid && get_field(changeset, :parent_uuid) == uuid,
      do: add_error(changeset, :parent_uuid, "cannot be the folder itself"),
      else: changeset
  end
end