diff --git a/lib/philomena/commissions.ex b/lib/philomena/commissions.ex index 10326b14..f0d152cb 100644 --- a/lib/philomena/commissions.ex +++ b/lib/philomena/commissions.ex @@ -49,8 +49,8 @@ defmodule Philomena.Commissions do {:error, %Ecto.Changeset{}} """ - def create_commission(attrs \\ %{}) do - %Commission{} + def create_commission(user, attrs \\ %{}) do + Ecto.build_assoc(user, :commission) |> Commission.changeset(attrs) |> Repo.insert() end diff --git a/lib/philomena/commissions/commission.ex b/lib/philomena/commissions/commission.ex index 1e89257a..10577785 100644 --- a/lib/philomena/commissions/commission.ex +++ b/lib/philomena/commissions/commission.ex @@ -26,8 +26,56 @@ defmodule Philomena.Commissions.Commission do def changeset(commission, attrs) do commission |> cast(attrs, [:information, :contact, :will_create, :will_not_create, :open, :sheet_image_id, :categories]) - |> validate_required([:user, :information, :contact, :open]) + |> drop_blank_categories() + |> validate_required([:user_id, :information, :contact, :open]) |> validate_length(:information, max: 700, count: :bytes) |> validate_length(:contact, max: 700, count: :bytes) + |> validate_subset(:categories, Keyword.values(categories())) + end + + defp drop_blank_categories(changeset) do + categories = + changeset + |> get_field(:categories) + |> Enum.filter(& &1 not in [nil, ""]) + + change(changeset, categories: categories) + end + + def categories do + [ + "Anthro": "Anthro", + "Canon Characters": "Canon Characters", + "Comics": "Comics", + "Fetish Art": "Fetish Art", + "Human and EqG": "Human and EqG", + "NSFW": "NSFW", + "Original Characters": "Original Characters", + "Original Species": "Original Species", + "Pony": "Pony", + "Requests": "Requests", + "Safe": "Safe", + "Shipping": "Shipping", + "Violence and Gore": "Violence and Gore" + ] + end + + def types do + [ + "Sketch", + "Colored Sketch", + "Inked", + "Flat Color", + "Vector", + "Cel Shaded", + "Fully Shaded", + "Traditional", + "Pixel Art", + "Animation", + "Crafted Item", + "Sculpture", + "Plushie", + "Other" + ] end end diff --git a/lib/philomena/users/ability.ex b/lib/philomena/users/ability.ex index ed2c036b..b8b2f601 100644 --- a/lib/philomena/users/ability.ex +++ b/lib/philomena/users/ability.ex @@ -1,6 +1,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do alias Philomena.Users.User alias Philomena.Comments.Comment + alias Philomena.Commissions.Commission alias Philomena.Conversations.Conversation alias Philomena.Images.Image alias Philomena.Forums.Forum @@ -64,6 +65,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do # View user links they've created def can?(%User{id: id}, :show, %UserLink{user_id: id}), do: true + # Edit their commissions + def can?(%User{id: id}, action, %Commission{user_id: id}) when action in [:edit, :update, :delete], do: true + # View non-deleted images def can?(_user, action, Image) when action in [:new, :create, :index], diff --git a/lib/philomena_web.ex b/lib/philomena_web.ex index 24c39e3b..2fcddf06 100644 --- a/lib/philomena_web.ex +++ b/lib/philomena_web.ex @@ -42,6 +42,7 @@ defmodule PhilomenaWeb do import PhilomenaWeb.ErrorHelpers import PhilomenaWeb.Gettext + import PhoenixMTM.Helpers alias PhilomenaWeb.Router.Helpers, as: Routes # Wrong way around for convenience diff --git a/lib/philomena_web/controllers/profile/commission_controller.ex b/lib/philomena_web/controllers/profile/commission_controller.ex index e097264e..8176eb4b 100644 --- a/lib/philomena_web/controllers/profile/commission_controller.ex +++ b/lib/philomena_web/controllers/profile/commission_controller.ex @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do item_descriptions = commission.items - |> Enum.map(&%{body: &1.description}) + |> Enum.map(&%{body: &1.description }) |> Renderer.render_collection(conn) item_add_ons = @@ -29,10 +29,10 @@ defmodule PhilomenaWeb.Profile.CommissionController do [information, contact, will_create, will_not_create] = Renderer.render_collection( [ - %{body: commission.information}, - %{body: commission.contact}, - %{body: commission.will_create}, - %{body: commission.will_not_create} + %{body: commission.information || ""}, + %{body: commission.contact || ""}, + %{body: commission.will_create || ""}, + %{body: commission.will_not_create || ""} ], conn ) @@ -55,6 +55,49 @@ defmodule PhilomenaWeb.Profile.CommissionController do render(conn, "new.html", changeset: changeset) end + def create(conn, %{"commission" => commission_params}) do + user = conn.assigns.current_user + + case Commissions.create_commission(user, commission_params) do + {:ok, _commission} -> + conn + |> put_flash(:info, "Commission successfully created.") + |> redirect(to: Routes.profile_commission_path(conn, :show, user)) + + {:error, changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def edit(conn, _params) do + changeset = Commissions.change_commission(conn.assigns.user.commission) + render(conn, "edit.html", changeset: changeset) + end + + def update(conn, %{"commission" => commission_params}) do + commission = conn.assigns.user.commission + + case Commissions.update_commission(commission, commission_params) do + {:ok, _commission} -> + conn + |> put_flash(:info, "Commission successfully updated.") + |> redirect(to: Routes.profile_commission_path(conn, :show, conn.assigns.user)) + + {:error, changeset} -> + render(conn, "edit.html", changeset: changeset) + end + end + + def delete(conn, _params) do + commission = conn.assigns.user.commission + + {:ok, _commission} = Commissions.delete_commission(commission) + + conn + |> put_flash(:info, "Commission deleted successfully.") + |> redirect(to: Routes.commission_path(conn, :index)) + end + defp ensure_commission(conn, _opts) do case is_nil(conn.assigns.user.commission) do true -> PhilomenaWeb.NotFoundPlug.call(conn) diff --git a/lib/philomena_web/templates/commission/_directory_sidebar.html.slime b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime index 15088e9b..df244d72 100644 --- a/lib/philomena_web/templates/commission/_directory_sidebar.html.slime +++ b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime @@ -1,38 +1,3 @@ -elixir: - categories = [ - "Anthro": :category_anthro, - "Canon Characters": :category_canon_characters, - "Comics": :category_comics, - "Fetish Art": :category_fetish_art, - "Human and EqG": :category_human_and_eqg, - "NSFW": :category_nsfw, - "Original Characters": :category_original_characters, - "Original Species": :category_original_species, - "Pony": :category_pony, - "Requests": :category_requests, - "Safe": :category_safe, - "Shipping": :category_shipping, - "Violence and Gore": :category_violence_and_gore - ] - - types = [ - [key: "-", value: ""], - "Sketch", - "Colored Sketch", - "Inked", - "Flat Color", - "Vector", - "Cel Shaded", - "Fully Shaded", - "Traditional", - "Pixel Art", - "Animation", - "Crafted Item", - "Sculpture", - "Plushie", - "Other" - ] - .block .block__header span.block__header__title Search @@ -40,7 +5,7 @@ elixir: = form_for @conn, Routes.commission_path(@conn, :index), [as: :commission, method: "get", class: "hform"], fn f -> .field = label f, :categories, "Art Categories:" - = for {name, value} <- categories do + = for {name, value} <- categories() do .field => checkbox f, value, checked_value: name, name: "commission[category][]", class: "checkbox spacing-right", hidden_input: false => label f, value, name @@ -48,7 +13,7 @@ elixir: br .field = label f, :item_type, "Commission Type:" - .field = select f, :item_type, types, class: "input" + .field = select f, :item_type, types(), class: "input" br diff --git a/lib/philomena_web/templates/profile/commission/_form.html.slime b/lib/philomena_web/templates/profile/commission/_form.html.slime index 10e8b1a4..86efff34 100644 --- a/lib/philomena_web/templates/profile/commission/_form.html.slime +++ b/lib/philomena_web/templates/profile/commission/_form.html.slime @@ -5,30 +5,34 @@ .field => label f, :information, "General Information:" - = textarea f, :information, class: "input input--wide input--text", placeholder: "A general overview about your commissions." + = textarea f, :information, class: "input input--wide input--text", placeholder: "A general overview about your commissions.", required: true + = error_tag f, :information .field => label f, :contact, "Contact Information:" - = textarea f, :contact, class: "input input--wide input--text", placeholder: "How you would like potential customers to contact you (PM, Discord, Email, etc). Remember that this information will be publicly visible." + = textarea f, :contact, class: "input input--wide input--text", placeholder: "How you would like potential customers to contact you (PM, Discord, Email, etc). Remember that this information will be publicly visible.", required: true + = error_tag f, :contact .field => label f, :will_create, "Content you are particularly interested in drawing or creating (optional):" = textarea f, :will_create, class: "input input--wide input--text", placeholder: "List specific content you are willing to accept commissions for." + = error_tag f, :will_create .field => label f, :will_not_create, "Content you will not draw or create (optional):" = textarea f, :will_not_create, class: "input input--wide input--text", placeholder: "List specific content you are not willing to accept commissions for." + = error_tag f, :will_not_create .field => label f, :categories, "Art Categories:" br - /= f.collection_check_boxes :categories, Commission::CATEGORIES.sort_by(&:downcase), :itself, :itself do |b| - span.commission__category - => b.label - = b.check_box + = collection_checkboxes f, :categories, categories(), wrapper: &Phoenix.HTML.Tag.content_tag(:span, &1, class: "commission__category") + = error_tag f, :categories .field => label f, :sheet_image_id, "Image ID of your commissions sheet (optional but recommended):" br = number_input f, :sheet_image_id, class: "input", placeholder: "1227409" + = error_tag f, :sheet_image_id .field = label f, :open, "Currently accepting commissions." do => checkbox f, :open, class: "checkbox" + = error_tag f, :open br = submit "Save", class: "button" diff --git a/lib/philomena_web/templates/profile/commission/_listing_items.html.slime b/lib/philomena_web/templates/profile/commission/_listing_items.html.slime index 93fa76d3..48ec4fd1 100644 --- a/lib/philomena_web/templates/profile/commission/_listing_items.html.slime +++ b/lib/philomena_web/templates/profile/commission/_listing_items.html.slime @@ -3,6 +3,14 @@ span.block__header__title Available Items and Prices .block__content + + = if not Enum.any?(@commission.items) do + = if current?(@user, @conn.assigns.current_user) do + p You have not added any items to your commissions sheet yet. + p Your listing will not appear in search results until you list at least one item. + - else + p This artist has not added any items yet. Please check back later. + table.table thead tr diff --git a/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime b/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime index c83add82..e9c52a8d 100644 --- a/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime +++ b/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime @@ -12,13 +12,14 @@ br - strong> Price Range: - - {min, max} = Enum.min_max_by(@commission.items, & &1.base_price) - | $ - => Decimal.round(min.base_price, 2) |> Decimal.to_string() - | - $ - => Decimal.round(max.base_price, 2) |> Decimal.to_string() - ' USD + = if Enum.any?(@commission.items) do + strong> Price Range: + - {min, max} = Enum.min_max_by(@commission.items, & &1.base_price) + | $ + => Decimal.round(min.base_price, 2) |> Decimal.to_string() + | - $ + => Decimal.round(max.base_price, 2) |> Decimal.to_string() + ' USD br br @@ -65,16 +66,16 @@ = render partial: 'profiles/user_link_area' / Options block -/.block +.block .block__header span.block__header__title Options .block__content - - if can? :edit, @user.commission - = link_to 'Edit this listing', edit_commission_path(@user.commission) + = if can?(@conn, :edit, @commission) do + = link "Edit this listing", to: Routes.profile_commission_path(@conn, :edit, @user) br - = link_to 'Delete this listing', commission_path(@user.commission), data: { confirm: t('commissions.confirm_delete_listing') }, method: :delete + = link "Delete this listing", to: Routes.profile_commission_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure about that?", method: :delete] br - = link_to 'Report this listing', new_report_path(reportable_class: 'commission', reportable_id: @user.commission.id) + /= link_to 'Report this listing', new_report_path(reportable_class: 'commission', reportable_id: @user.commission.id) / Share block .block diff --git a/lib/philomena_web/templates/profile/commission/edit.html.slime b/lib/philomena_web/templates/profile/commission/edit.html.slime new file mode 100644 index 00000000..aa6bab71 --- /dev/null +++ b/lib/philomena_web/templates/profile/commission/edit.html.slime @@ -0,0 +1,5 @@ +h1 Edit Commission Listing +p + = link "Back to commission", to: Routes.profile_commission_path(@conn, :show, @user) + += render PhilomenaWeb.Profile.CommissionView, "_form.html", changeset: @changeset, action: Routes.profile_commission_path(@conn, :update, @user), conn: @conn \ No newline at end of file diff --git a/lib/philomena_web/templates/profile/commission/show.html.slime b/lib/philomena_web/templates/profile/commission/show.html.slime index b9dbaad3..3589646c 100644 --- a/lib/philomena_web/templates/profile/commission/show.html.slime +++ b/lib/philomena_web/templates/profile/commission/show.html.slime @@ -6,13 +6,13 @@ h1 / Side column .column-layout__left - = render PhilomenaWeb.Profile.CommissionView, "_listing_sidebar.html", commission: @commission, rendered: @rendered, conn: @conn + = render PhilomenaWeb.Profile.CommissionView, "_listing_sidebar.html", commission: @commission, user: @user, rendered: @rendered, conn: @conn / Main column .column-layout__main / Commission sheet block - = render PhilomenaWeb.Profile.CommissionView, "_listing_sheet.html", commission: @commission, conn: @conn + = render PhilomenaWeb.Profile.CommissionView, "_listing_sheet.html", commission: @commission, user: @user, conn: @conn / Types and prices block - = render PhilomenaWeb.Profile.CommissionView, "_listing_items.html", commission: @commission, items: @items, conn: @conn \ No newline at end of file + = render PhilomenaWeb.Profile.CommissionView, "_listing_items.html", commission: @commission, user: @user, items: @items, conn: @conn \ No newline at end of file diff --git a/lib/philomena_web/views/commission_view.ex b/lib/philomena_web/views/commission_view.ex index e5e2743a..3d4ae339 100644 --- a/lib/philomena_web/views/commission_view.ex +++ b/lib/philomena_web/views/commission_view.ex @@ -1,3 +1,8 @@ defmodule PhilomenaWeb.CommissionView do use PhilomenaWeb, :view + + alias Philomena.Commissions.Commission + + def categories, do: [[key: "-", value: ""] | Commission.categories()] + def types, do: Commission.types() end diff --git a/lib/philomena_web/views/profile/commission_view.ex b/lib/philomena_web/views/profile/commission_view.ex index 5b76e2b3..c8e4a82f 100644 --- a/lib/philomena_web/views/profile/commission_view.ex +++ b/lib/philomena_web/views/profile/commission_view.ex @@ -1,3 +1,10 @@ defmodule PhilomenaWeb.Profile.CommissionView do use PhilomenaWeb, :view + + alias Philomena.Commissions.Commission + + def categories, do: Commission.categories() + + def current?(%{id: id}, %{id: id}), do: true + def current?(_user1, _user2), do: false end diff --git a/mix.exs b/mix.exs index 12adaee5..d30195f3 100644 --- a/mix.exs +++ b/mix.exs @@ -59,7 +59,8 @@ defmodule Philomena.MixProject do {:bamboo, "~> 1.2"}, {:bamboo_smtp, "~> 1.7"}, {:remote_ip, "~> 0.2.0"}, - {:briefly, "~> 0.3.0"} + {:briefly, "~> 0.3.0"}, + {:phoenix_mtm, "~> 1.0.0"} ] end diff --git a/mix.lock b/mix.lock index ae373527..71ffe421 100644 --- a/mix.lock +++ b/mix.lock @@ -39,6 +39,7 @@ "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.1", "274a4b07c4adbdd7785d45a8b0bb57634d0b4f45b18d2c508b26c0344bd59b8f", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_mtm": {:hex, :phoenix_mtm, "1.0.0", "36a2292f84f0712aa4fa029cb6618d9388371d70951b0269bdf372df576aab56", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, "phoenix_slime": {:hex, :phoenix_slime, "0.12.0", "0d5f2b600b8a69dad361a987fdfc836bc71cdce373ce11abade4f6548880f0bf", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:slime, "~> 1.0", [hex: :slime, repo: "hexpm", optional: false]}], "hexpm"}, "plug": {:hex, :plug, "1.8.3", "12d5f9796dc72e8ac9614e94bda5e51c4c028d0d428e9297650d09e15a684478", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},