diff --git a/lib/who_need_help/activities.ex b/lib/who_need_help/activities.ex index 027088b..805cde7 100644 --- a/lib/who_need_help/activities.ex +++ b/lib/who_need_help/activities.ex @@ -102,6 +102,18 @@ defmodule WhoNeedHelp.Activities do participant.activity_id == activity.id and participant.user_id == ^user.id and participant.status in [:requested, :approved] ) + |> where( + [activity], + activity.creator_id not in subquery( + from block in Block, where: block.blocker_id == ^user.id, select: block.blocked_id + ) + ) + |> where( + [activity], + activity.creator_id not in subquery( + from block in Block, where: block.blocked_id == ^user.id, select: block.blocker_id + ) + ) |> before_my_activity(cursor) |> order_by([activity], desc: activity.starts_at, desc: activity.id) |> limit(^(limit + 1)) diff --git a/lib/who_need_help/trust.ex b/lib/who_need_help/trust.ex index 795389e..775018a 100644 --- a/lib/who_need_help/trust.ex +++ b/lib/who_need_help/trust.ex @@ -48,61 +48,76 @@ defmodule WhoNeedHelp.Trust do attrs = stringify_keys(attrs) with {:ok, _limit} <- authorize_action(scope, :review) do - Repo.transact(fn -> - current = - Assignment - |> where([current], current.id == ^assignment.id) - |> lock("FOR UPDATE") - |> Repo.one() + result = + Repo.transact(fn -> + current = + Assignment + |> where([current], current.id == ^assignment.id) + |> lock("FOR UPDATE") + |> Repo.one() - if current do - request = Repo.get!(HelpRequest, current.request_id) + if current do + request = Repo.get!(HelpRequest, current.request_id) - cond do - current.status != :completed -> - {:error, :forbidden} + cond do + current.status != :completed -> + {:error, :forbidden} - user.id not in [current.helper_id, request.requester_id] -> - {:error, :forbidden} + user.id not in [current.helper_id, request.requester_id] -> + {:error, :forbidden} - true -> - reviewee_id = - if user.id == current.helper_id, - do: request.requester_id, - else: current.helper_id + true -> + reviewee_id = + if user.id == current.helper_id, + do: request.requester_id, + else: current.helper_id - with {:ok, review} <- - %Review{} - |> Review.changeset( - Map.merge(attrs, %{ - "assignment_id" => current.id, - "reviewer_id" => user.id, - "reviewee_id" => reviewee_id - }) - ) - |> Repo.insert(), - reviews <- Repo.all(from r in Review, where: r.assignment_id == ^current.id), - true <- length(reviews) <= 2, - revealed? <- length(reviews) == 2, - {_count, _rows} <- - maybe_reveal_reviews(current.id, revealed?), - {:ok, _audit} <- - audit(user.id, "review.submitted", "assignment", current.id, %{ - "revealed" => revealed? - }) do - {:ok, review} - else - false -> {:error, :invalid_review_count} - other -> other - end + with {:ok, review} <- + %Review{} + |> Review.changeset( + Map.merge(attrs, %{ + "assignment_id" => current.id, + "reviewer_id" => user.id, + "reviewee_id" => reviewee_id + }) + ) + |> Repo.insert(), + reviews <- Repo.all(from r in Review, where: r.assignment_id == ^current.id), + true <- length(reviews) <= 2, + revealed? <- length(reviews) == 2, + {_count, _rows} <- + maybe_reveal_reviews(current.id, revealed?), + {:ok, _audit} <- + audit(user.id, "review.submitted", "assignment", current.id, %{ + "revealed" => revealed? + }) do + {:ok, review} + else + false -> {:error, :invalid_review_count} + other -> other + end + end + else + {:error, :not_found} end - else - {:error, :not_found} - end - end) + end) + + with {:ok, review} <- result do + :ok = Help.notify_request_updated(assignment.request_id) + {:ok, review} + end end end + def review_submitted?(%Scope{user: %User{id: user_id}}, %Assignment{id: assignment_id}) do + Repo.exists?( + from review in Review, + where: review.assignment_id == ^assignment_id and review.reviewer_id == ^user_id + ) + end + + def review_submitted?(_scope, _assignment), do: false + defp maybe_reveal_reviews(assignment_id, true) do Repo.update_all(from(r in Review, where: r.assignment_id == ^assignment_id), set: [revealed_at: DateTime.utc_now(:second)] diff --git a/lib/who_need_help_web/form_params.ex b/lib/who_need_help_web/form_params.ex new file mode 100644 index 0000000..efeaf47 --- /dev/null +++ b/lib/who_need_help_web/form_params.ex @@ -0,0 +1,19 @@ +defmodule WhoNeedHelpWeb.FormParams do + @moduledoc false + + @live_view_unused_prefix "_unused_" + + def drop_unused_structured_fields(%{"structured_data" => data} = params) + when is_map(data) do + data = + Map.reject(data, fn {key, _value} -> + key + |> to_string() + |> String.starts_with?(@live_view_unused_prefix) + end) + + Map.put(params, "structured_data", data) + end + + def drop_unused_structured_fields(params), do: params +end diff --git a/lib/who_need_help_web/live/activity_live/new.ex b/lib/who_need_help_web/live/activity_live/new.ex index e54c991..0040f6d 100644 --- a/lib/who_need_help_web/live/activity_live/new.ex +++ b/lib/who_need_help_web/live/activity_live/new.ex @@ -3,6 +3,7 @@ defmodule WhoNeedHelpWeb.ActivityLive.New do alias WhoNeedHelp.{Activities, Catalog} alias WhoNeedHelp.Activities.Activity + alias WhoNeedHelpWeb.FormParams @impl true def mount(_params, _session, socket) do @@ -17,6 +18,8 @@ defmodule WhoNeedHelpWeb.ActivityLive.New do @impl true def handle_event("validate", %{"activity" => params}, socket) do + params = FormParams.drop_unused_structured_fields(params) + changeset = %Activity{} |> Activities.change_activity(normalize_datetimes(params)) @@ -29,6 +32,8 @@ defmodule WhoNeedHelpWeb.ActivityLive.New do end def handle_event("save", %{"activity" => params}, socket) do + params = FormParams.drop_unused_structured_fields(params) + case Activities.create_activity(socket.assigns.current_scope, normalize_datetimes(params)) do {:ok, activity} -> {:noreply, diff --git a/lib/who_need_help_web/live/activity_live/show.ex b/lib/who_need_help_web/live/activity_live/show.ex index 20d6275..e1e7182 100644 --- a/lib/who_need_help_web/live/activity_live/show.ex +++ b/lib/who_need_help_web/live/activity_live/show.ex @@ -80,7 +80,10 @@ defmodule WhoNeedHelpWeb.ActivityLive.Show do params ) do {:ok, message} -> - {:noreply, put_realtime_message(socket, message)} + {:noreply, + socket + |> put_realtime_message(message) + |> push_event("reset-message-form", %{id: "activity-message-form"})} {:error, reason} -> {:noreply, put_flash(socket, :error, error_message(reason))} @@ -120,7 +123,8 @@ defmodule WhoNeedHelpWeb.ActivityLive.Show do socket |> assign(:report_form, report_form()) |> assign(:report_message_id, nil) - |> put_flash(:info, gettext("Report sent to moderators."))} + |> put_flash(:info, gettext("Report sent to moderators.")) + |> push_event("reset-message-form", %{id: "activity-report-form"})} {:error, reason} -> {:noreply, put_flash(socket, :error, error_message(reason))} @@ -527,7 +531,10 @@ defmodule WhoNeedHelpWeb.ActivityLive.Show do
- <.form for={@report_form} phx-submit="report" class="mt-4 space-y-2"> + <.form + for={@report_form} + id="activity-report-form" + phx-submit="report" + class="mt-4 space-y-2" + >{gettext("Proposals and votes guide moderators. Approval remains a human decision.")}
- <.form for={@form} phx-submit="propose" class="mt-7 space-y-4 rounded-3xl bg-base-200 p-6"> + <.form + for={@form} + id="category-proposal-form" + phx-submit="propose" + class="mt-7 space-y-4 rounded-3xl bg-base-200 p-6" + > <.input field={@form[:proposed_name]} label={gettext("Proposed category")} diff --git a/lib/who_need_help_web/live/request_live/new.ex b/lib/who_need_help_web/live/request_live/new.ex index 97c2729..9b45498 100644 --- a/lib/who_need_help_web/live/request_live/new.ex +++ b/lib/who_need_help_web/live/request_live/new.ex @@ -4,6 +4,7 @@ defmodule WhoNeedHelpWeb.RequestLive.New do alias WhoNeedHelp.Catalog alias WhoNeedHelp.Help alias WhoNeedHelp.Help.HelpRequest + alias WhoNeedHelpWeb.FormParams @impl true def mount(_params, _session, socket) do @@ -28,6 +29,8 @@ defmodule WhoNeedHelpWeb.RequestLive.New do @impl true def handle_event("validate", %{"help_request" => params}, socket) do + params = FormParams.drop_unused_structured_fields(params) + changeset = %HelpRequest{} |> Help.change_request(normalize_expiry(params)) @@ -40,6 +43,8 @@ defmodule WhoNeedHelpWeb.RequestLive.New do end def handle_event("save", %{"help_request" => params}, socket) do + params = FormParams.drop_unused_structured_fields(params) + case Help.create_request(socket.assigns.current_scope, normalize_expiry(params)) do {:ok, request} -> {:noreply, diff --git a/lib/who_need_help_web/live/request_live/show.ex b/lib/who_need_help_web/live/request_live/show.ex index 3120a01..5577e72 100644 --- a/lib/who_need_help_web/live/request_live/show.ex +++ b/lib/who_need_help_web/live/request_live/show.ex @@ -258,7 +258,8 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do socket |> assign(:report_form, report_form()) |> assign(:report_message_id, nil) - |> put_flash(:info, gettext("Report sent to moderators."))} + |> put_flash(:info, gettext("Report sent to moderators.")) + |> push_event("reset-message-form", %{id: "request-report-form"})} {:error, reason} -> {:noreply, put_flash(socket, :error, message(reason))} @@ -422,6 +423,7 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do ) |> assign(:assignment, assignment) |> assign(:participant, participant) + |> assign(:review_submitted, Trust.review_submitted?(socket.assigns.current_scope, assignment)) |> assign(:other_user_id, other_user_id) |> assign( :blocked_by_current, @@ -816,7 +818,15 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do{gettext("Your review is revealed only after both participants submit.")}
- <.form for={@review_form} phx-submit="review" class="mt-4 space-y-3"> ++ {gettext("Review saved. It appears after both participants review.")} +
+ <.form + :if={!@review_submitted} + for={@review_form} + phx-submit="review" + class="mt-4 space-y-3" + > <.input field={@review_form[:rating]} type="select" @@ -1068,7 +1078,12 @@ defmodule WhoNeedHelpWeb.RequestLive.Show do > {gettext("Unblock this user")} - <.form for={@report_form} phx-submit="report" class="mt-4 space-y-2"> + <.form + for={@report_form} + id="request-report-form" + phx-submit="report" + class="mt-4 space-y-2" + >