Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v0.0.12 (2022-03-07)
- Add support for array fields

## v0.0.11 (2021-08-12)
- Update dependencies
- Allow custom error messages to be set on cast (#35)
Expand Down
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config
import Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
Expand Down
77 changes: 52 additions & 25 deletions lib/waffle_ecto/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ defmodule Waffle.Ecto.Schema do
|> convert_params_to_binary()
|> Map.take(allowed_param_keys)
|> check_and_apply_scope(scope, options)
|> Enum.into(%{})
|> Map.new()
end

Ecto.Changeset.cast(changeset_or_data, waffle_params, allowed)
Expand All @@ -90,31 +90,58 @@ defmodule Waffle.Ecto.Schema do
def do_apply_changes(%{__meta__: _} = data), do: data

def check_and_apply_scope(params, scope, options) do
Enum.reduce(params, [], fn
# Don't wrap nil casts in the scope object
{field, nil}, fields ->
[{field, nil} | fields]

# Allow casting Plug.Uploads
{field, upload = %{__struct__: Plug.Upload}}, fields ->
[{field, {upload, scope}} | fields]

# Allow casting binary data structs
{field, upload = %{filename: filename, binary: binary}}, fields
when is_binary(filename) and is_binary(binary) ->
[{field, {upload, scope}} | fields]

{field, upload = %{filename: filename, path: path}}, fields
when is_binary(filename) and is_binary(path) ->
path = String.trim(path)
upload = %{upload | path: path}
if path_allowed?(path, options), do: [{field, {upload, scope}} | fields], else: fields

# If casting a binary (path), ensure we've explicitly allowed paths
{field, path}, fields when is_binary(path) ->
path = String.trim(path)
if path_allowed?(path, options), do: [{field, {path, scope}} | fields], else: fields
params
|> Enum.reduce([], fn {field, value}, fields ->
[{field, apply_scope(value, scope, options)} | fields]
end)
|> Enum.reject(fn
{_field, :invalid} -> true
{_field, values} when is_list(values) -> Enum.any?(values, &(&1 == :invalid))
_else -> false
end)
end

# Don't wrap nil casts in the scope object
def apply_scope(nil, _scope, _options) do
nil
end

def apply_scope(values, scope, options) when is_list(values) do
Enum.map(values, &apply_scope(&1, scope, options))
end

# Allow casting already uploaded files
def apply_scope(%{file_name: filename, updated_at: %NaiveDateTime{}} = existing_file, _scope, _options)
when is_binary(filename) do
existing_file
end

# Allow casting Plug.Uploads
def apply_scope(%{__struct__: Plug.Upload} = upload, scope, _options) do
{upload, scope}
end

# Allow casting binary data structs
def apply_scope(%{filename: filename, binary: binary} = upload, scope, _options)
when is_binary(filename) and is_binary(binary) do
{upload, scope}
end

# If casting a binary (path), ensure we've explicitly allowed paths
def apply_scope(%{filename: filename, path: path} = upload, scope, options)
when is_binary(filename) and is_binary(path) do
path = String.trim(path)

if path_allowed?(path, options) do
{%{upload | path: path}, scope}
else
:invalid
end
end

def apply_scope(path, scope, options) when is_binary(path) do
path = String.trim(path)
if path_allowed?(path, options), do: {path, scope}, else: :invalid
end

defp path_allowed?(path, options) do
Expand Down
42 changes: 23 additions & 19 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
defmodule Waffle.Ecto.Mixfile do
use Mix.Project

@version "0.0.11"
@version "0.0.12"

def project do
[app: :waffle_ecto,
version: @version,
elixir: "~> 1.4",
elixirc_paths: elixirc_paths(Mix.env),
deps: deps(),
docs: docs(),

# Hex
description: description(),
package: package()]
[
app: :waffle_ecto,
version: @version,
elixir: "~> 1.4",
elixirc_paths: elixirc_paths(Mix.env()),
deps: deps(),
docs: docs(),

# Hex
description: description(),
package: package()
]
end

# Configuration for the OTP application
Expand All @@ -27,7 +29,7 @@ defmodule Waffle.Ecto.Mixfile do

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
defp elixirc_paths(_), do: ["lib"]

defp description do
"""
Expand All @@ -36,10 +38,12 @@ defmodule Waffle.Ecto.Mixfile do
end

defp package do
[maintainers: ["Boris Kuznetsov"],
licenses: ["Apache 2.0"],
links: %{"GitHub" => "https://github.com/elixir-waffle/waffle_ecto"},
files: ~w(mix.exs README.md CHANGELOG.md lib)]
[
maintainers: ["Boris Kuznetsov"],
licenses: ["Apache 2.0"],
links: %{"GitHub" => "https://github.com/elixir-waffle/waffle_ecto"},
files: ~w(mix.exs README.md CHANGELOG.md lib)
]
end

defp docs do
Expand All @@ -51,11 +55,11 @@ defmodule Waffle.Ecto.Mixfile do

defp deps do
[
{:waffle, "~> 1.0"},
{:ecto, "~> 3.0"},
{:waffle, "~> 1.1"},
{:ecto, "~> 3.13"},
{:mock, "~> 0.3", only: :test},
{:ex_doc, ">= 0.23.0", only: :dev},
{:credo, "~> 1.4", only: [:dev, :test], runtime: false}
{:credo, "~> 1.7", only: [:dev, :test], runtime: false}
]
end
end
Loading