diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 9de4eccc4d..3cf4123b6a 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -23,8 +23,8 @@ defmodule Pleroma.Constants do "assigned_account", "rules", "content_type", - "participants", - "participant_count" + "participations", + "participation_count" ] ) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 7ce7975323..ea5a421b89 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -525,7 +525,7 @@ def create_poll_notifications(%Activity{} = activity) do def create_event_notifications(%Activity{} = activity) do with %Object{data: %{"type" => "Event", "actor" => actor} = data} <- Object.normalize(activity) do - participations = + participations = case data do %{"participations" => participations} when is_list(participations) -> participations _ -> [] diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index b43cf0ec0d..344516389f 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -77,6 +77,9 @@ defmacro event_object_fields do field(:joinMode, :string, default: "free") embeds_one(:location, PlaceValidator) + + field(:participation_count, :integer, default: 0) + field(:participations, {:array, ObjectValidators.ObjectID}, default: []) end end end diff --git a/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex index 2c8d7d32d1..af6cc4db45 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_event_operation.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaEventOperation do alias OpenApiSpex.Operation alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.AccountOperation + alias Pleroma.Web.ApiSpec.Schemas.Account alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.Schemas.ParticipationRequest @@ -48,6 +49,7 @@ def participations_operation do "application/json", AccountOperation.array_of_accounts() ), + 403 => Operation.response("Error", "application/json", ApiError), 404 => Operation.response("Not Found", "application/json", ApiError) } } @@ -68,6 +70,7 @@ def participation_requests_operation do "application/json", array_of_participation_requests() ), + 403 => Operation.response("Forbidden", "application/json", ApiError), 404 => Operation.response("Not Found", "application/json", ApiError) } } @@ -87,6 +90,7 @@ def participate_operation do %Schema{ type: :object, properties: %{ + account: Account, participation_message: %Schema{ type: :string, description: "Why the user wants to participate" @@ -97,6 +101,7 @@ def participate_operation do ), responses: %{ 200 => event_response(), + 400 => Operation.response("Error", "application/json", ApiError), 404 => Operation.response("Not Found", "application/json", ApiError) } } @@ -112,6 +117,7 @@ def unparticipate_operation do parameters: [id_param()], responses: %{ 200 => event_response(), + 400 => Operation.response("Error", "application/json", ApiError), 404 => Operation.response("Not Found", "application/json", ApiError) } } @@ -158,6 +164,7 @@ defp create_request do }, status: %Schema{ type: :string, + nullable: true, description: "Text description of the event." }, banner_id: %Schema{ diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index f079c092a2..c39876a7c7 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -346,11 +346,15 @@ def join_helper(user, id, participation_message) do end def leave(%User{ap_id: participant_ap_id} = user, event_id) do - with %Activity{} = join_activity <- Utils.get_existing_join(participant_ap_id, event_id), + with %Activity{data: %{"object" => event_ap_id}} <- Activity.get_by_id(event_id), + %Activity{} = join_activity <- Utils.get_existing_join(participant_ap_id, event_ap_id), {:ok, undo, _} <- Builder.undo(user, join_activity), {:ok, activity, _} <- Pipeline.common_pipeline(undo, local: true) do {:ok, activity} else + nil -> + {:error, dgettext("errors", "Not participating in the event")} + _ -> {:error, dgettext("errors", "Could not remove join activity")} end diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 8ee6a2706c..2e02c34e66 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -111,16 +111,14 @@ defp event_object(draft) do emoji = Map.merge(Pleroma.Emoji.Formatter.get_emoji_map(draft.full_payload), draft.emoji) object = - draft.params - |> Map.take([:name]) + %{} + |> Map.put("name", draft.params[:name]) |> Map.put("type", "Event") |> Map.put("to", draft.to) |> Map.put("cc", draft.cc) |> Map.put("content", draft.content_html) |> Map.put("actor", draft.user.ap_id) - # |> Map.put("startTime", draft.params[:start_time]) - # |> Map.put("endTime", draft.params[:end_time]) - |> Map.put("joinMode", draft.params[:join_mode]) + |> Map.put("joinMode", draft.params[:join_mode] || "free") |> Map.put("tag", Keyword.values(draft.tags) |> Enum.uniq()) |> Map.put("emoji", emoji) @@ -337,8 +335,8 @@ defp event_date(draft) do else object = draft.object - |> Map.put("startTime", start_time) - |> Map.put("endTime", end_time) + |> Map.put("startTime", start_time |> DateTime.to_iso8601()) + |> Map.put("endTime", end_time |> DateTime.to_iso8601()) %__MODULE__{draft | object: object} end @@ -346,7 +344,7 @@ defp event_date(draft) do _ -> object = draft.object - |> Map.put("startTime", start_time) + |> Map.put("startTime", start_time |> DateTime.to_iso8601()) %__MODULE__{draft | object: object} end diff --git a/lib/pleroma/web/pleroma_api/controllers/event_controller.ex b/lib/pleroma/web/pleroma_api/controllers/event_controller.ex index fade4f033d..0d423236c2 100644 --- a/lib/pleroma/web/pleroma_api/controllers/event_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/event_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.EventController do use Pleroma.Web, :controller import Pleroma.Web.ControllerHelper, - only: [add_link_headers: 2, try_render: 3] + only: [add_link_headers: 2, json_response: 3, try_render: 3] require Ecto.Query @@ -30,6 +30,18 @@ defmodule Pleroma.Web.PleromaAPI.EventController do when action in [:accept_participation_request, :reject_participation_request] ) + plug( + :assign_event_activity + when action in [ + :participations, + :participation_requests, + :accept_participation_request, + :reject_participation_request, + :participate, + :unparticipate + ] + ) + plug( OAuthScopesPlug, %{scopes: ["write"]} @@ -51,6 +63,10 @@ defmodule Pleroma.Web.PleromaAPI.EventController do defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEventOperation def create(%{assigns: %{user: user}, body_params: params} = conn, _) do + params = + params + |> Map.put(:status, Map.get(params, :status, "")) + with {:ok, activity} <- CommonAPI.event(user, params) do conn |> put_view(StatusView) @@ -72,10 +88,8 @@ def create(%{assigns: %{user: user}, body_params: params} = conn, _) do end end - def participations(%{assigns: %{user: user}} = conn, %{id: activity_id}) do - with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), - {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, - %Object{data: %{"participations" => participations}} <- + def participations(%{assigns: %{user: user, event_activity: activity}} = conn, _) do + with %Object{data: %{"participations" => participations}} <- Object.normalize(activity, fetch: false) do users = User @@ -93,58 +107,83 @@ def participations(%{assigns: %{user: user}} = conn, %{id: activity_id}) do end def participation_requests( - %{assigns: %{user: %{ap_id: user_ap_id} = for_user}} = conn, - %{id: activity_id} = params - ) do - with %Activity{object: %Object{data: %{"id" => ap_id, "actor" => ^user_ap_id}}} <- - Activity.get_by_id_with_object(activity_id) do - params = + %{assigns: %{user: %{ap_id: user_ap_id} = for_user, event_activity: activity}} = conn, params - |> Map.put(:type, "Join") - |> Map.put(:object, ap_id) - |> Map.put(:state, "pending") + ) do + case activity do + %Activity{actor: ^user_ap_id, data: %{"object" => ap_id}} -> + params = + params + |> Map.put(:type, "Join") + |> Map.put(:object, ap_id) + |> Map.put(:state, "pending") - activities = - [] - |> ActivityPub.fetch_activities_query(params) - |> Pagination.fetch_paginated(params) + activities = + [] + |> ActivityPub.fetch_activities_query(params) + |> Pagination.fetch_paginated(params) - conn - |> add_link_headers(activities) - |> put_view(EventView) - |> render("participation_requests.json", - activities: activities, - for: for_user, - as: :activity - ) + conn + |> add_link_headers(activities) + |> put_view(EventView) + |> render("participation_requests.json", + activities: activities, + for: for_user, + as: :activity + ) + + %Activity{} -> + render_error(conn, :forbidden, "Can't get participation requests") + + {:error, error} -> + json_response(conn, :bad_request, %{error: error}) end end - def participate(%{assigns: %{user: user}, body_params: params} = conn, %{id: event_id}) do - with {:ok, _} <- CommonAPI.join(user, event_id, params), - %Activity{} = activity <- Activity.get_by_id(event_id) do + def participate(%{assigns: %{user: %{ap_id: actor}, event_activity: %{actor: actor}}} = conn, _) do + render_error(conn, :bad_request, "Can't join your own event") + end + + def participate( + %{assigns: %{user: user, event_activity: activity}, body_params: params} = conn, + _ + ) do + with {:ok, _} <- CommonAPI.join(user, activity.id, params) do conn |> put_view(StatusView) |> try_render("show.json", activity: activity, for: user, as: :activity) end end - def unparticipate(%{assigns: %{user: user}} = conn, %{id: event_id}) do - with {:ok, _} <- CommonAPI.leave(user, event_id), - %Activity{} = activity <- Activity.get_by_id(event_id) do + def unparticipate( + %{assigns: %{user: %{ap_id: actor}, event_activity: %{actor: actor}}} = conn, + _ + ) do + render_error(conn, :bad_request, "Can't leave your own event") + end + + def unparticipate(%{assigns: %{user: user, event_activity: activity}} = conn, _) do + with {:ok, _} <- CommonAPI.leave(user, activity.id) do conn |> put_view(StatusView) |> try_render("show.json", activity: activity, for: user, as: :activity) + else + {:error, error} -> + json_response(conn, :bad_request, %{error: error}) end end def accept_participation_request( - %{assigns: %{user: for_user, participant: participant}} = conn, - %{id: event_id} + %{ + assigns: %{ + user: for_user, + participant: participant, + event_activity: %Activity{data: %{"object" => ap_id}} = activity + } + } = conn, + _ ) do - with %Activity{data: %{"object" => ap_id}} <- Activity.get_by_id(event_id), - {:ok, _} <- CommonAPI.accept_join_request(for_user, participant, ap_id), - %Activity{} = activity <- Activity.get_by_id(event_id) do + with {:ok, _} <- CommonAPI.accept_join_request(for_user, participant, ap_id) do conn |> put_view(StatusView) |> try_render("show.json", activity: activity, for: for_user, as: :activity) @@ -152,12 +191,16 @@ def accept_participation_request( end def reject_participation_request( - %{assigns: %{user: for_user, participant: participant}} = conn, - %{id: event_id} + %{ + assigns: %{ + user: for_user, + participant: participant, + event_activity: %Activity{data: %{"object" => ap_id}} = activity + } + } = conn, + _ ) do - with %Activity{data: %{"object" => ap_id}} <- Activity.get_by_id(event_id), - {:ok, _} <- CommonAPI.reject_join_request(for_user, participant, ap_id), - %Activity{} = activity <- Activity.get_by_id(event_id) do + with {:ok, _} <- CommonAPI.reject_join_request(for_user, participant, ap_id) do conn |> put_view(StatusView) |> try_render("show.json", activity: activity, for: for_user, as: :activity) @@ -170,4 +213,13 @@ defp assign_participant(%{params: %{participant_id: id}} = conn, _) do nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt() end end + + defp assign_event_activity(%{assigns: %{user: user}, params: %{id: event_id}} = conn, _) do + with %Activity{} = activity <- Activity.get_by_id(event_id), + {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)} do + assign(conn, :event_activity, activity) + else + nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt() + end + end end diff --git a/lib/pleroma/workers/event_reminder_worker.ex b/lib/pleroma/workers/event_reminder_worker.ex index 20e33af1b4..edf26ee5d7 100644 --- a/lib/pleroma/workers/event_reminder_worker.ex +++ b/lib/pleroma/workers/event_reminder_worker.ex @@ -28,17 +28,17 @@ defp find_event_activity(activity_id) do def schedule_event_reminder(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do with %Object{data: %{"type" => "Event", "startTime" => start_time}} <- Object.normalize(activity), - {:ok, start_time} <- NaiveDateTime.from_iso8601(start_time), + {:ok, start_time} <- DateTime.from_iso8601(start_time), :lt <- - NaiveDateTime.compare( - start_time |> NaiveDateTime.add(60 * 60 * -2, :second), - NaiveDateTime.utc_now() + DateTime.compare( + start_time |> DateTime.add(60 * 60 * -2, :second), + DateTime.utc_now() ) do %{ op: "event_reminder", activity_id: activity_id } - |> new(scheduled_at: start_time |> NaiveDateTime.add(60 * 60 * -2, :second)) + |> new(scheduled_at: start_time |> DateTime.add(60 * 60 * -2, :second)) |> Oban.insert() else _ -> {:error, activity} diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 0d475bec0d..c4e3509a16 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -133,7 +133,13 @@ test "creates notification for event join request" do user = insert(:user) other_user = insert(:user) - {:ok, activity} = CommonAPI.event(user, %{name: "test event", status: "", join_mode: "restricted"}) + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "restricted", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) CommonAPI.join(other_user, activity.id) @@ -145,7 +151,13 @@ test "creates notification for event join approval" do user = insert(:user) other_user = insert(:user) - {:ok, activity} = CommonAPI.event(user, %{name: "test event", status: "", join_mode: "restricted"}) + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "restricted", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) CommonAPI.join(other_user, activity.id) @@ -159,7 +171,13 @@ test "doesn't create notification for events without participation approval" do user = insert(:user) other_user = insert(:user) - {:ok, activity} = CommonAPI.event(user, %{name: "test event", status: "", join_mode: "free"}) + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "free", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) CommonAPI.join(other_user, activity.id) diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index 01c02dab3e..5a13922077 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -796,7 +796,7 @@ test "increases replies count", %{user: user} do assert object.data["repliesCount"] == 2 end - test "increates quotes count", %{user: user} do + test "increases quotes count", %{user: user} do user2 = insert(:user) {:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"}) diff --git a/test/pleroma/web/pleroma_api/controllers/event_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/event_controller_test.exs new file mode 100644 index 0000000000..6f70916864 --- /dev/null +++ b/test/pleroma/web/pleroma_api/controllers/event_controller_test.exs @@ -0,0 +1,298 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.EventControllerTest do + use Pleroma.Web.ConnCase + use Oban.Testing, repo: Pleroma.Repo + + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.CommonAPI + + import Pleroma.Factory + + describe "POST /api/v1/pleroma/events" do + setup do + user = insert(:user) + %{user: user, conn: conn} = oauth_access(["write"], user: user) + [current_user: user, conn: conn] + end + + test "creates an event", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/events", %{ + "name" => "Event name", + "start_time" => "2023-01-01T01:00:00.000Z", + "end_time" => "2023-01-01T04:00:00.000Z", + "join_mode" => "free" + }) + + assert %{ + "pleroma" => %{ + "event" => %{ + "name" => "Event name", + "join_mode" => "free" + } + } + } = json_response_and_validate_schema(conn, 200) + end + + test "can't create event that ends before its start", %{conn: conn} do + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/events", %{ + "name" => "Event name", + "start_time" => "2023-01-01T04:00:00.000Z", + "end_time" => "2022-12-31T04:00:00.000Z", + "join_mode" => "free" + }) + + assert json_response_and_validate_schema(conn, 422) == %{ + "error" => "Event can't end before its start" + } + end + end + + test "GET /api/v1/pleroma/events/:id/participations" do + %{conn: conn} = oauth_access(["read"]) + + user_one = insert(:user) + user_two = insert(:user) + user_three = insert(:user) + + {:ok, activity} = + CommonAPI.event(user_one, %{ + name: "test event", + status: "", + join_mode: "free", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + CommonAPI.join(user_two, activity.id) + CommonAPI.join(user_three, activity.id) + + conn = + conn + |> get("/api/v1/pleroma/events/#{activity.id}/participations") + + assert response = json_response_and_validate_schema(conn, 200) + assert length(response) == 2 + end + + describe "GET /api/v1/pleroma/events/:id/participation_requests" do + setup do + user = insert(:user) + %{user: user, conn: conn} = oauth_access(["read"], user: user) + [current_user: user, conn: conn] + end + + test "show participation requests", %{conn: conn, current_user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "restricted", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + CommonAPI.join(other_user, activity.id, %{ + participation_message: "I'm interested in this event" + }) + + conn = + conn + |> get("/api/v1/pleroma/events/#{activity.id}/participation_requests") + + assert [ + %{ + "participation_message" => "I'm interested in this event" + } + ] = response = json_response_and_validate_schema(conn, 200) + + assert length(response) == 1 + end + + test "don't display requests if not an author", %{conn: conn} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.event(other_user, %{ + name: "test event", + status: "", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + conn = + conn + |> get("/api/v1/pleroma/events/#{activity.id}/participation_requests") + + assert %{"error" => "Can't get participation requests"} = + json_response_and_validate_schema(conn, 403) + end + end + + describe "POST /api/v1/pleroma/events/:id/participate" do + setup do + user = insert(:user) + %{user: user, conn: conn} = oauth_access(["write"], user: user) + [current_user: user, conn: conn] + end + + test "joins an event", %{conn: conn} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.event(other_user, %{ + name: "test event", + status: "", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + conn = + conn + |> post("/api/v1/pleroma/events/#{activity.id}/participate") + + assert json_response_and_validate_schema(conn, 200) + + assert %{ + data: %{ + "participation_count" => 1 + } + } = Object.get_by_ap_id(activity.data["object"]) + end + + test "can't participate in your own event", %{conn: conn, current_user: user} do + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + conn = + conn + |> post("/api/v1/pleroma/events/#{activity.id}/participate") + + assert json_response_and_validate_schema(conn, :bad_request) == %{ + "error" => "Can't join your own event" + } + end + end + + describe "POST /api/v1/pleroma/events/:id/unparticipate" do + setup do + user = insert(:user) + %{user: user, conn: conn} = oauth_access(["write"], user: user) + [current_user: user, conn: conn] + end + + test "leaves an event", %{conn: conn, current_user: user} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.event(other_user, %{ + name: "test event", + status: "", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + CommonAPI.join(user, activity.id) + + conn = + conn + |> post("/api/v1/pleroma/events/#{activity.id}/unparticipate") + + assert json_response_and_validate_schema(conn, 200) + + assert %{ + data: %{ + "participation_count" => 0 + } + } = Object.get_by_ap_id(activity.data["object"]) + end + + test "can't leave event you are not participating in", %{conn: conn} do + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.event(other_user, %{ + name: "test event", + status: "", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + conn = + conn + |> post("/api/v1/pleroma/events/#{activity.id}/unparticipate") + + assert json_response_and_validate_schema(conn, :bad_request) == %{ + "error" => "Not participating in the event" + } + end + end + + test "POST /api/v1/pleroma/events/:id/participation_requests/:participant_id/accept" do + [user, %{ap_id: ap_id} = other_user] = insert_pair(:user) + %{user: user, conn: conn} = oauth_access(["write"], user: user) + + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "restricted", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + CommonAPI.join(other_user, activity.id) + + conn = + conn + |> post( + "/api/v1/pleroma/events/#{activity.id}/participation_requests/#{other_user.id}/accept" + ) + + assert json_response_and_validate_schema(conn, 200) + + assert %{ + data: %{ + "participations" => [^ap_id], + "participation_count" => 1 + } + } = Object.get_by_ap_id(activity.data["object"]) + + assert %{data: %{"state" => "accept"}} = + Utils.get_existing_join(other_user.ap_id, activity.data["object"]) + end + + test "POST /api/v1/pleroma/events/:id/participation_requests/:participant_id/reject" do + [user, other_user] = insert_pair(:user) + %{user: user, conn: conn} = oauth_access(["write"], user: user) + + {:ok, activity} = + CommonAPI.event(user, %{ + name: "test event", + status: "", + join_mode: "restricted", + start_time: DateTime.from_iso8601("2023-01-01T01:00:00.000Z") |> elem(1) + }) + + CommonAPI.join(other_user, activity.id) + + conn = + conn + |> post( + "/api/v1/pleroma/events/#{activity.id}/participation_requests/#{other_user.id}/reject" + ) + + assert json_response_and_validate_schema(conn, 200) + + assert %{data: %{"state" => "reject"}} = + Utils.get_existing_join(other_user.ap_id, activity.data["object"]) + end +end