Skip to content

Commit

Permalink
fixes #191: support the avatar upload by an image URL
Browse files Browse the repository at this point in the history
    This commit will add the support to upload the avatar
    of a person by providing the image URL.
    That feature is available from the admin website.

replace nested ifs with the cond statement

Changelog.Arc.Ecto.Schema module should be removed
  • Loading branch information
joebew42 committed Feb 5, 2018
1 parent d05158f commit 6092d8d
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 3 deletions.
76 changes: 76 additions & 0 deletions lib/changelog/arc_ecto/schema.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# This is a patched version of the Arc.Ecto.Schema (of the arc_ecto library) module
# url: https://github.com/stavro/arc_ecto/blob/master/lib/arc_ecto/schema.ex
# we introduced the support of the `allow_urls` feature
# we have to wait until this feature will be merged in the upstream
# before we can remove this file and use the library's version again.
defmodule Changelog.Arc.Ecto.Schema do
defmacro __using__(_) do
quote do
import Changelog.Arc.Ecto.Schema
end
end

defmacro cast_attachments(changeset_or_data, params, allowed, options \\ []) do
quote bind_quoted: [changeset_or_data: changeset_or_data,
params: params,
allowed: allowed,
options: options] do

# If given a changeset, apply the changes to obtain the underlying data
scope = case changeset_or_data do
%Ecto.Changeset{} -> Ecto.Changeset.apply_changes(changeset_or_data)
%{__meta__: _} -> changeset_or_data
end

# Cast supports both atom and string keys, ensure we're matching on both.
allowed = Enum.map(allowed, fn key ->
case key do
key when is_binary(key) -> key
key when is_atom(key) -> Atom.to_string(key)
end
end)

arc_params = case params do
:invalid ->
:invalid
%{} ->
params
|> Changelog.Arc.Ecto.Schema.convert_params_to_binary
|> Map.take(allowed)
|> Enum.reduce([], 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]

# If casting a binary (path), ensure we've explicitly allowed paths or urls
{field, path}, fields when is_binary(path) ->
cond do
Keyword.get(options, :allow_urls, false) and Regex.match?( ~r/^https?:\/\// , path) -> [{field, {path, scope}} | fields]
Keyword.get(options, :allow_paths, false) -> [{field, {path, scope}} | fields]
true -> fields
end
end)
|> Enum.into(%{})
end

cast(changeset_or_data, arc_params, allowed)
end
end

def convert_params_to_binary(params) do
Enum.reduce(params, nil, fn
{key, _value}, nil when is_binary(key) ->
nil

{key, _value}, _ when is_binary(key) ->
raise ArgumentError, "expected params to be a map with atoms or string keys, " <>
"got a map with mixed keys: #{inspect params}"

{key, value}, acc when is_atom(key) ->
Map.put(acc || %{}, Atom.to_string(key), value)

end) || params
end
end
2 changes: 1 addition & 1 deletion lib/changelog/data/data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Changelog.Data do

quote do
use Ecto.Schema
use Arc.Ecto.Schema
use Changelog.Arc.Ecto.Schema
use Timex.Ecto.Timestamps

import Ecto
Expand Down
2 changes: 1 addition & 1 deletion lib/changelog/data/person.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ defmodule Changelog.Person do

defp changeset_with_allowed_params(struct, params, allowed) do
struct
|> cast_attachments(params, ~w(avatar))
|> cast_attachments(params, ~w(avatar), allow_urls: true)
|> cast(params, allowed)
|> validate_required([:name, :email, :handle])
|> validate_format(:website, Regexp.http, message: Regexp.http_message)
Expand Down
7 changes: 6 additions & 1 deletion lib/changelog_web/templates/admin/person/_form.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@
<br/>
<% end %>
<%= error_message(f, :avatar) %>
<%= file_input f, :avatar %>
<div class="field">
<%= text_input f, :avatar, placeholder: "Avatar image URL", value: "" %>
</div>
<div class="field">
<%= file_input f, :avatar %>
</div>
</div>

<div class="two fields">
Expand Down
11 changes: 11 additions & 0 deletions test/changelog/data/person_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ defmodule Changelog.PersonTest do
refute changeset.valid?
end

test "admin_changeset with a local file path image URL attribute" do
person = insert(:person)
local_file_path = File.cwd! <> "/test/fixtures/avatar600x600.png"
attrs = Map.put(@valid_attrs, :avatar, local_file_path)

changeset = Person.admin_changeset(person, attrs)

assert changeset.valid?
refute Map.has_key?(changeset.changes, :avatar)
end

test "encoded_auth and decoded_auth" do
user = %Person{email: "[email protected]", auth_token: "8675309"}
{:ok, encoded} = Person.encoded_auth(user)
Expand Down
Binary file added test/fixtures/avatar600x600.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6092d8d

Please sign in to comment.