diff --git a/lib/atomic/accounts.ex b/lib/atomic/accounts.ex index a53cf0a8f..b451b0aca 100644 --- a/lib/atomic/accounts.ex +++ b/lib/atomic/accounts.ex @@ -472,6 +472,24 @@ defmodule Atomic.Accounts do |> Repo.update() end + @doc """ + Updates the user cv. + + ## Examples + + iex> update_user_cv(user, %{cv: ...}) + {:ok, %User{}} + + iex> update_user_cv(user, %{cv: ...}) + {:error, %Ecto.Changeset{}} + + """ + def update_user_cv(%User{} = user, attrs \\ %{}) do + user + |> User.cv_changeset(attrs) + |> Repo.update() + end + @doc """ Updates the user. @@ -484,10 +502,17 @@ defmodule Atomic.Accounts do {:error, %Ecto.Changeset{}} """ - def update_user(%User{} = user, attrs \\ %{}, _after_save \\ &{:ok, &1}) do + def update_user( + %User{} = user, + attrs \\ %{}, + after_save_cv \\ &{:ok, &1}, + after_save_image \\ &{:ok, &1} + ) do user |> User.changeset(attrs) |> Repo.update() + |> after_save(after_save_cv) + |> after_save(after_save_image) end @doc """ diff --git a/lib/atomic/accounts/user.ex b/lib/atomic/accounts/user.ex index ca67ec77a..9e76462c0 100644 --- a/lib/atomic/accounts/user.ex +++ b/lib/atomic/accounts/user.ex @@ -7,7 +7,7 @@ defmodule Atomic.Accounts.User do alias Atomic.Accounts.Course alias Atomic.Activities.ActivityEnrollment alias Atomic.Organizations.{Membership, Organization} - alias Atomic.Uploaders.ProfilePicture + alias Atomic.Uploaders.{CV, ProfilePicture} @required_fields ~w(email password)a @optional_fields ~w(name slug role phone_number confirmed_at course_id current_organization_id)a @@ -26,6 +26,7 @@ defmodule Atomic.Accounts.User do field :phone_number, :string field :profile_picture, ProfilePicture.Type + field :cv, CV.Type field :role, Ecto.Enum, values: @roles, default: :student belongs_to :course, Course belongs_to :current_organization, Organization @@ -60,12 +61,24 @@ defmodule Atomic.Accounts.User do |> validate_password(opts) end + @doc """ + A user changeset for updating the user's profile picture. + """ def picture_changeset(user, attrs) do user |> cast(attrs, @required_fields ++ @optional_fields) |> cast_attachments(attrs, [:profile_picture]) end + @doc """ + A user changeset for updating the user's CV. + """ + def cv_changeset(user, attrs) do + user + |> cast(attrs, @required_fields ++ @optional_fields) + |> cast_attachments(attrs, [:cv]) + end + @doc """ A user changeset for updating the user. """ diff --git a/lib/atomic/uploader.ex b/lib/atomic/uploader.ex index 6e0f8d049..fa5407941 100644 --- a/lib/atomic/uploader.ex +++ b/lib/atomic/uploader.ex @@ -5,7 +5,7 @@ defmodule Atomic.Uploader do """ @versions [:original, :medium, :thumb] - @extensions_whitelist ~w(.svg .jpg .jpeg .png) + @extensions_whitelist ~w(.svg .jpg .jpeg .png .pdf .docx) defmacro __using__(_) do quote do diff --git a/lib/atomic/uploaders/cv.ex b/lib/atomic/uploaders/cv.ex new file mode 100644 index 000000000..6e75529e1 --- /dev/null +++ b/lib/atomic/uploaders/cv.ex @@ -0,0 +1,11 @@ +defmodule Atomic.Uploaders.CV do + @moduledoc """ + Uploader for CVs. + """ + use Atomic.Uploader + alias Atomic.Accounts.User + + def storage_dir(_version, {_file, %User{} = scope}) do + "uploads/atomic/user_cvs/#{scope.id}" + end +end diff --git a/lib/atomic_web/live/profile_live/form_component.ex b/lib/atomic_web/live/profile_live/form_component.ex index 82fe062f4..35bcea9ef 100644 --- a/lib/atomic_web/live/profile_live/form_component.ex +++ b/lib/atomic_web/live/profile_live/form_component.ex @@ -3,12 +3,13 @@ defmodule AtomicWeb.ProfileLive.FormComponent do alias Atomic.Accounts - @extensions_whitelist ~w(.jpg .jpeg .gif .png) + @extensions_whitelist ~w(.jpg .jpeg .gif .png .pdf .docx) @impl true def mount(socket) do {:ok, socket + |> allow_upload(:cv, accept: @extensions_whitelist, max_entries: 1) |> allow_upload(:picture, accept: @extensions_whitelist, max_entries: 1)} end @@ -54,6 +55,7 @@ defmodule AtomicWeb.ProfileLive.FormComponent do case Accounts.update_user( user, Map.put(user_params, "email", user.email), + &consume_cv_data(socket, &1), &consume_image_data(socket, &1) ) do {:ok, _user} -> @@ -68,21 +70,48 @@ defmodule AtomicWeb.ProfileLive.FormComponent do end defp consume_image_data(socket, user) do - consume_uploaded_entries(socket, :image, fn %{path: path}, entry -> - Accounts.update_user(user, %{ - "image" => %Plug.Upload{ - content_type: entry.client_type, - filename: entry.client_name, - path: path - } - }) - end) - |> case do - [{:ok, user}] -> - {:ok, user} - - _errors -> - {:ok, user} + if Map.has_key?(socket.assigns.uploads, :image) do + consume_uploaded_entries(socket, :image, fn %{path: path}, entry -> + Accounts.update_user_picture(user, %{ + "image" => %Plug.Upload{ + content_type: entry.client_type, + filename: entry.client_name, + path: path + } + }) + end) + |> case do + [{:ok, user}] -> + {:ok, user} + + _errors -> + {:ok, user} + end end + + {:ok, user} + end + + defp consume_cv_data(socket, user) do + if Map.has_key?(socket.assigns.uploads, :cv) do + consume_uploaded_entries(socket, :cv, fn %{path: path}, entry -> + Accounts.update_user_cv(user, %{ + "cv" => %Plug.Upload{ + content_type: entry.client_type, + filename: entry.client_name, + path: path + } + }) + end) + |> case do + [{:ok, user}] -> + {:ok, user} + + _errors -> + {:ok, user} + end + end + + {:ok, user} end end diff --git a/lib/atomic_web/live/profile_live/form_component.html.heex b/lib/atomic_web/live/profile_live/form_component.html.heex index f9de1c7f2..e046ac809 100644 --- a/lib/atomic_web/live/profile_live/form_component.html.heex +++ b/lib/atomic_web/live/profile_live/form_component.html.heex @@ -46,6 +46,10 @@ ) %>
<%= error_tag(f, :phone_number) %>
+
+ <%= label(f, :Upload_CV, class: "mb-1 text-sm font-medium text-gray-700") %> + <.live_file_input upload={@uploads.cv} class="" /> +
<.live_file_input upload={@uploads.picture} class="hidden" /> diff --git a/priv/fake/teste_cv.pdf b/priv/fake/teste_cv.pdf new file mode 100644 index 000000000..caa39949d Binary files /dev/null and b/priv/fake/teste_cv.pdf differ diff --git a/priv/repo/migrations/20221014155230_create_users_auth_tables.exs b/priv/repo/migrations/20221014155230_create_users_auth_tables.exs index 645fcd55e..7242f3d18 100644 --- a/priv/repo/migrations/20221014155230_create_users_auth_tables.exs +++ b/priv/repo/migrations/20221014155230_create_users_auth_tables.exs @@ -13,6 +13,7 @@ defmodule Atomic.Repo.Migrations.CreateUsersAuthTables do add :hashed_password, :string, null: false add :confirmed_at, :naive_datetime add :profile_picture, :string + add :cv, :string add :role, :string, null: false, default: "student" add :current_organization_id, diff --git a/test/atomic/accounts_test.exs b/test/atomic/accounts_test.exs index b5dc09419..fdef6b802 100644 --- a/test/atomic/accounts_test.exs +++ b/test/atomic/accounts_test.exs @@ -511,4 +511,20 @@ defmodule Atomic.AccountsTest do refute inspect(%User{password: "123456"}) =~ "password: \"123456\"" end end + + describe "upload CV" do + test "uploads a CV" do + user = insert(:user) + + cv = %Plug.Upload{ + content_type: "application/pdf", + filename: "teste_cv.pdf", + path: "priv/fake/teste_cv.pdf" + } + + {:ok, user} = Accounts.update_user_cv(user, %{"cv" => cv}) + assert user.cv + assert cv.filename == user.cv.file_name + end + end end