diff --git a/lib/philomena/commissions/commission.ex b/lib/philomena/commissions/commission.ex index 80eb5549..2df2e800 100644 --- a/lib/philomena/commissions/commission.ex +++ b/lib/philomena/commissions/commission.ex @@ -2,12 +2,14 @@ defmodule Philomena.Commissions.Commission do use Ecto.Schema import Ecto.Changeset + alias Philomena.Commissions.Item alias Philomena.Images.Image alias Philomena.Users.User schema "commissions" do belongs_to :user, User belongs_to :sheet_image, Image + has_many :items, Item field :open, :boolean field :categories, {:array, :string}, default: [] diff --git a/lib/philomena_web/controllers/commission_controller.ex b/lib/philomena_web/controllers/commission_controller.ex new file mode 100644 index 00000000..a2155f44 --- /dev/null +++ b/lib/philomena_web/controllers/commission_controller.ex @@ -0,0 +1,86 @@ +defmodule PhilomenaWeb.CommissionController do + use PhilomenaWeb, :controller + + alias Philomena.Commissions.{Item, Commission} + alias Philomena.Repo + import Ecto.Query + + plug PhilomenaWeb.FilterBannedUsersPlug when action in [:new, :create, :edit, :update, :destroy] + plug :load_and_authorize_resource, model: Commission + + def index(conn, params) do + commissions = + commission_search(params["commission"]) + |> Repo.paginate(conn.assigns.scrivener) + + render(conn, "index.html", commissions: commissions, layout_class: "layout--wide") + end + + defp commission_search(attrs) when is_map(attrs) do + item_type = presence(attrs["item_type"]) + categories = presence(attrs["category"]) + keywords = presence(attrs["keywords"]) + price_min = to_f(presence(attrs["price_min"]) || 0) + price_max = to_f(presence(attrs["price_max"]) || 9999) + + query = + commission_search(nil) + |> where([_c, ci], ci.base_price > ^price_min and ci.base_price < ^price_max) + + query = + if item_type do + query + |> where([_c, ci], ci.item_type == ^item_type) + else + query + end + + query = + if categories do + query + |> where([c, _ci], fragment("? @> ?", c.categories, ^categories)) + else + query + end + + query = + if keywords do + query + |> where([c, _ci], ilike(c.information, ^like_sanitize(keywords)) or ilike(c.will_create, ^like_sanitize(keywords))) + else + query + end + + query + end + + defp commission_search(_attrs) do + from c in Commission, + where: c.open == true, + where: c.commission_items_count > 0, + inner_join: ci in Item, on: ci.commission_id == c.id, + group_by: c.id, + order_by: [asc: fragment("random()")], + preload: [user: [awards: :badge], items: [example_image: :tags]] + end + + defp presence(nil), + do: nil + defp presence([]), + do: nil + defp presence(string) when is_binary(string), + do: if(String.trim(string) == "", do: nil, else: string) + defp presence(object), + do: object + + defp to_f(input) do + case Float.parse(to_string(input)) do + {float, _rest} -> float + _error -> 0.0 + end + end + + defp like_sanitize(input) do + "%" <> String.replace(input, ["\\", "%", "_"], &<<"\\", &1>>) <> "%" + end +end \ No newline at end of file diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index 2f5612aa..1a1b434c 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -97,6 +97,7 @@ defmodule PhilomenaWeb.Router do resources "/profiles", ProfileController, only: [:show] resources "/captchas", CaptchaController, only: [:create] resources "/posts", PostController, only: [:index] + resources "/commissions", CommissionController, only: [:index, :show] get "/:id", ImageController, :show end diff --git a/lib/philomena_web/templates/commission/_directory_results.html.slime b/lib/philomena_web/templates/commission/_directory_results.html.slime new file mode 100644 index 00000000..a3aad473 --- /dev/null +++ b/lib/philomena_web/templates/commission/_directory_results.html.slime @@ -0,0 +1,49 @@ +elixir: + route = fn p -> Routes.commission_path(@conn, :index, p) end + pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @commissions, route: route, conn: @conn + +.block + .block__header + span.block__header__title Open Commissions + = pagination + + .block__content + = cond do + - Enum.any?(@commissions) -> + = for c <- @commissions do + .block.commission + .block__content.flex.flex--no-wrap + .flex__fixed.spacing-right + = render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: c, conn: @conn + + .flex__grow.commission__listing_body + span.commission__listing_artist + = render PhilomenaWeb.UserAttributionView, "_user.html", object: c, badges: true, conn: @conn + + .commission__listing__body_text + p + strong> Price Range: + = :io_lib.format("$~.2f - $~.2f USD", [c.minimum_price, c.maximum_price]) + + p + strong> Categories: + = Enum.join(c.categories, ", ") + + p + strong> Offers: + = Enum.map(c.items, & &1.item_type) |> Enum.join(", ") + + p + strong> Example Artwork: + + br + + = for item <- Enum.take_random(c.items, 5) do + = render PhilomenaWeb.ImageView, "_image_container.html", image: item.example_image, conn: @conn + + p + strong + = link "More information", to: Routes.commission_path(@conn, :show, c) + + - true -> + p We couldn't find any commission listings to display. Sorry! \ No newline at end of file diff --git a/lib/philomena_web/templates/commission/_directory_sidebar.html.slime b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime new file mode 100644 index 00000000..15088e9b --- /dev/null +++ b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime @@ -0,0 +1,64 @@ +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 + .block__content + = 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 + .field + => checkbox f, value, checked_value: name, name: "commission[category][]", class: "checkbox spacing-right", hidden_input: false + => label f, value, name + + br + + .field = label f, :item_type, "Commission Type:" + .field = select f, :item_type, types, class: "input" + + br + + .field = label f, :price_min, "Price:" + .field = number_input f, :price_min, class: "input input--short", placeholder: "At Least", step: "any", min: 0 + .field = number_input f, :price_max, class: "input input--short", placeholder: "At Most", step: "any", min: 0 + + br + + .field = label f, :keywords, "Search:" + .field = text_input f, :keywords, class: "input input--short", placeholder: "Keywords" + + = submit "Search", class: "button" \ No newline at end of file diff --git a/lib/philomena_web/templates/commission/index.html.slime b/lib/philomena_web/templates/commission/index.html.slime new file mode 100644 index 00000000..0581d86c --- /dev/null +++ b/lib/philomena_web/templates/commission/index.html.slime @@ -0,0 +1,18 @@ +h1 Commissions Directory + +.dnp-warning + h4 Disclaimer + p + ' This is only a directory meant to help connect artists offering + ' commissions with potential commissioners. We don't have any way + ' for users to make payments through the site, so we can't be held + ' responsible for any issues regarding payment. + a href="/pages/rules#9" More info. + +br + +.column-layout + .column-layout__left + = render PhilomenaWeb.CommissionView, "_directory_sidebar.html", conn: @conn + .column-layout__main + = render PhilomenaWeb.CommissionView, "_directory_results.html", commissions: @commissions, 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 new file mode 100644 index 00000000..e5e2743a --- /dev/null +++ b/lib/philomena_web/views/commission_view.ex @@ -0,0 +1,3 @@ +defmodule PhilomenaWeb.CommissionView do + use PhilomenaWeb, :view +end