From acd921432f53a46046a652ca8e990ee3ceb6c7fe Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 26 Jul 2021 17:23:42 +0200 Subject: [PATCH] Refactor checking permissions when managing events and tests Signed-off-by: Thomas Citharel --- lib/graphql/resolvers/event.ex | 91 ++- lib/mobilizon/events/events.ex | 1 + test/graphql/resolvers/event_test.exs | 790 +++++++++++++++----------- 3 files changed, 539 insertions(+), 343 deletions(-) diff --git a/lib/graphql/resolvers/event.ex b/lib/graphql/resolvers/event.ex index 1cc6a86d..8d69e759 100644 --- a/lib/graphql/resolvers/event.ex +++ b/lib/graphql/resolvers/event.ex @@ -255,11 +255,19 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do # See https://github.com/absinthe-graphql/absinthe/issues/490 with {:is_owned, %Actor{} = organizer_actor} <- User.owns_actor(user, organizer_actor_id), args <- Map.put(args, :options, args[:options] || %{}), + {:group_check, true} <- {:group_check, is_organizer_group_member?(args)}, args_with_organizer <- Map.put(args, :organizer_actor, organizer_actor), {:ok, %Activity{data: %{"object" => %{"type" => "Event"}}}, %Event{} = event} <- API.Events.create_event(args_with_organizer) do {:ok, event} else + {:group_check, false} -> + {:error, + dgettext( + "errors", + "Organizer profile doesn't have permission to create an event on behalf of this group" + )} + {:is_owned, nil} -> {:error, dgettext("errors", "Organizer profile is not owned by the user")} @@ -286,16 +294,21 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do # See https://github.com/absinthe-graphql/absinthe/issues/490 with args <- Map.put(args, :options, args[:options] || %{}), {:ok, %Event{} = event} <- Events.get_event_with_preload(event_id), - {:old_actor, {:is_owned, %Actor{}}} <- - {:old_actor, User.owns_actor(user, event.organizer_actor_id)}, - new_organizer_actor_id <- args |> Map.get(:organizer_actor_id, event.organizer_actor_id), - {:new_actor, {:is_owned, %Actor{} = organizer_actor}} <- - {:new_actor, User.owns_actor(user, new_organizer_actor_id)}, - args <- Map.put(args, :organizer_actor, organizer_actor), + %Actor{} = actor <- Users.get_actor_for_user(user), + {:ok, args} <- verify_profile_change(args, event, user, actor), + {:event_can_be_managed, true} <- + {:event_can_be_managed, can_event_be_updated_by?(event, actor)}, {:ok, %Activity{data: %{"object" => %{"type" => "Event"}}}, %Event{} = event} <- API.Events.update_event(args, event) do {:ok, event} else + {:event_can_be_managed, false} -> + {:error, + dgettext( + "errors", + "This profile doesn't have permission to update an event on behalf of this group" + )} + {:error, :event_not_found} -> {:error, dgettext("errors", "Event not found")} @@ -325,7 +338,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do with {:ok, %Event{local: is_local} = event} <- Events.get_event_with_preload(event_id), %Actor{id: actor_id} = actor <- Users.get_actor_for_user(user) do cond do - {:event_can_be_managed, true} == Event.can_be_managed_by(event, actor_id) -> + {:event_can_be_managed, true} == + {:event_can_be_managed, can_event_be_deleted_by?(event, actor)} -> do_delete_event(event, actor) role in [:moderator, :administrator] -> @@ -355,4 +369,67 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do {:ok, %{id: event.id}} end end + + defp is_organizer_group_member?(%{ + attributed_to_id: attributed_to_id, + organizer_actor_id: organizer_actor_id + }) + when not is_nil(attributed_to_id) do + Actors.is_member?(organizer_actor_id, attributed_to_id) && + Permission.can_create_group_object?(organizer_actor_id, attributed_to_id, %Event{}) + end + + defp is_organizer_group_member?(_), do: true + + defp verify_profile_change( + args, + %Event{attributed_to: %Actor{}}, + %User{} = _user, + %Actor{} = current_profile + ) do + # The organizer_actor has to be the current profile, because otherwise we're left with a possible remote organizer + args = Map.put(args, :organizer_actor, current_profile) + {:ok, args} + end + + defp verify_profile_change( + args, + %Event{organizer_actor: %Actor{id: organizer_actor_id}}, + %User{} = user, + %Actor{} = _actor + ) do + with {:old_actor, {:is_owned, %Actor{}}} <- + {:old_actor, User.owns_actor(user, organizer_actor_id)}, + new_organizer_actor_id <- args |> Map.get(:organizer_actor_id, organizer_actor_id), + {:new_actor, {:is_owned, %Actor{} = organizer_actor}} <- + {:new_actor, User.owns_actor(user, new_organizer_actor_id)}, + args <- Map.put(args, :organizer_actor, organizer_actor) do + {:ok, args} + end + end + + defp can_event_be_updated_by?( + %Event{attributed_to: %Actor{type: :Group}} = event, + %Actor{} = actor_member + ) do + Permission.can_update_group_object?(actor_member, event) + end + + defp can_event_be_updated_by?( + %Event{} = event, + %Actor{id: actor_member_id} + ) do + Event.can_be_managed_by?(event, actor_member_id) + end + + defp can_event_be_deleted_by?( + %Event{attributed_to: %Actor{type: :Group}} = event, + %Actor{} = actor_member + ) do + Permission.can_delete_group_object?(actor_member, event) + end + + defp can_event_be_deleted_by?(%Event{} = event, %Actor{id: actor_member_id}) do + Event.can_be_managed_by?(event, actor_member_id) + end end diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex index e410bd9d..c63b0aa4 100644 --- a/lib/mobilizon/events/events.ex +++ b/lib/mobilizon/events/events.ex @@ -153,6 +153,7 @@ defmodule Mobilizon.Events do def get_event_by_url!(url) do url |> event_by_url_query() + |> preload_for_event() |> Repo.one!() end diff --git a/test/graphql/resolvers/event_test.exs b/test/graphql/resolvers/event_test.exs index d2dc8c5f..4505236a 100644 --- a/test/graphql/resolvers/event_test.exs +++ b/test/graphql/resolvers/event_test.exs @@ -5,8 +5,11 @@ defmodule Mobilizon.Web.Resolvers.EventTest do import Mobilizon.Factory - alias Mobilizon.Events + alias Mobilizon.Actors.Actor + alias Mobilizon.{Events, Users} + alias Mobilizon.Events.Event alias Mobilizon.Service.Workers + alias Mobilizon.Users.User alias Mobilizon.GraphQL.AbsintheHelpers @@ -21,6 +24,15 @@ defmodule Mobilizon.Web.Resolvers.EventTest do category: "meeting" } + @find_event_query """ + query Event($uuid: UUID!) { + event(uuid: $uuid) { + uuid, + draft + } + } + """ + setup %{conn: conn} do user = insert(:user) actor = insert(:actor, user: user, preferred_username: "test") @@ -28,16 +40,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do {:ok, conn: conn, actor: actor, user: user} end - describe "Event Resolver" do - @find_event_query """ - query Event($uuid: UUID!) { - event(uuid: $uuid) { - uuid, - draft - } - } - """ - + describe "Find an event" do test "find_event/3 returns an event", context do event = @event @@ -66,7 +69,9 @@ defmodule Mobilizon.Web.Resolvers.EventTest do assert [%{"message" => "Event not found"}] = res["errors"] end + end + describe "create_event/3 for a regular profile" do @create_event_mutation """ mutation CreateEvent( $title: String!, @@ -76,6 +81,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do $status: EventStatus, $visibility: EventVisibility, $organizer_actor_id: ID!, + $attributed_to_id: ID, $online_address: String, $options: EventOptionsInput, $draft: Boolean @@ -88,6 +94,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do status: $status, visibility: $visibility, organizer_actor_id: $organizer_actor_id, + attributed_to_id: $attributed_to_id, online_address: $online_address, options: $options, draft: $draft @@ -629,30 +636,171 @@ defmodule Mobilizon.Web.Resolvers.EventTest do assert json_response(res, 200)["data"]["createEvent"]["picture"]["url"] end + end - test "update_event/3 should check the event exists", %{conn: conn, actor: _actor, user: user} do - mutation = """ - mutation { - updateEvent( - event_id: 45, - title: "my event updated" - ) { - title, - uuid, - tags { - title, - slug - } - } - } - """ + describe "create_event/3 on behalf of a group" do + @variables %{ + title: "come to my event", + description: "it will be fine", + begins_on: "2021-07-26T09:00:00Z" + } + + test "create_event/3 should check the member has permission to create a group event", %{ + conn: conn + } do + %User{} = user = insert(:user) + %Actor{id: group_id} = group = insert(:group) + + %Actor{id: member_not_approved_actor_id} = + member_not_approved_actor = insert(:actor, user: user) + + insert(:member, parent: group, actor: member_not_approved_actor) + %Actor{id: member_actor_id} = member_actor = insert(:actor, user: user) + insert(:member, parent: group, actor: member_actor, role: :member) + %Actor{id: moderator_actor_id} = moderator_actor = insert(:actor, user: user) + insert(:member, parent: group, actor: moderator_actor, role: :moderator) + %Actor{id: not_member_actor_id} = insert(:actor, user: user) + + variables = Map.put(@variables, :attributed_to_id, "#{group_id}") res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @create_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{member_not_approved_actor_id}") + ) - assert hd(json_response(res, 200)["errors"])["message"] == "Event not found" + assert res["data"]["createEvent"] == nil + + assert hd(res["errors"])["message"] == + "Organizer profile doesn't have permission to create an event on behalf of this group" + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @create_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{not_member_actor_id}") + ) + + assert res["data"]["createEvent"] == nil + + assert hd(res["errors"])["message"] == + "Organizer profile doesn't have permission to create an event on behalf of this group" + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @create_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{member_actor_id}") + ) + + assert res["data"]["createEvent"] == nil + + assert hd(res["errors"])["message"] == + "Organizer profile doesn't have permission to create an event on behalf of this group" + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @create_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{moderator_actor_id}") + ) + + assert res["errors"] == nil + assert res["data"]["createEvent"] != nil + end + end + + @update_event_mutation """ + mutation updateEvent( + $eventId: ID! + $title: String + $description: String + $beginsOn: DateTime + $endsOn: DateTime + $status: EventStatus + $visibility: EventVisibility + $joinOptions: EventJoinOptions + $draft: Boolean + $tags: [String] + $picture: MediaInput + $onlineAddress: String + $phoneAddress: String + $organizerActorId: ID + $attributedToId: ID + $category: String + $physicalAddress: AddressInput + $options: EventOptionsInput + $contacts: [Contact] + ) { + updateEvent( + eventId: $eventId + title: $title + description: $description + beginsOn: $beginsOn + endsOn: $endsOn + status: $status + visibility: $visibility + joinOptions: $joinOptions + draft: $draft + tags: $tags + picture: $picture + onlineAddress: $onlineAddress + phoneAddress: $phoneAddress + organizerActorId: $organizerActorId + attributedToId: $attributedToId + category: $category + physicalAddress: $physicalAddress + options: $options + contacts: $contacts + ) { + id, + uuid, + url, + title + draft + description + beginsOn + endsOn + status + tags { + title, + slug + }, + online_address, + phone_address, + category, + options { + maximumAttendeeCapacity, + showRemainingAttendeeCapacity + }, + physicalAddress { + url, + geom, + street + } + picture { + name + } + } + } + """ + + describe "update_event/3" do + test "update_event/3 should check the event exists", %{conn: conn, actor: _actor, user: user} do + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{eventId: 45, title: "my event updated"} + ) + + assert hd(res["errors"])["message"] == "Event not found" end test "update_event/3 should check the user can change the organizer", %{ @@ -663,29 +811,15 @@ defmodule Mobilizon.Web.Resolvers.EventTest do event = insert(:event, organizer_actor: actor) actor2 = insert(:actor) - mutation = """ - mutation { - updateEvent( - title: "my event updated", - event_id: #{event.id} - organizer_actor_id: #{actor2.id} - ) { - title, - uuid, - tags { - title, - slug - } - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{eventId: event.id, title: "my event updated", organizerActorId: actor2.id} + ) - assert hd(json_response(res, 200)["errors"])["message"] == + assert hd(res["errors"])["message"] == "You can't attribute this event to this profile." end @@ -696,28 +830,15 @@ defmodule Mobilizon.Web.Resolvers.EventTest do } do event = insert(:event) - mutation = """ - mutation { - updateEvent( - title: "my event updated", - event_id: #{event.id} - ) { - title, - uuid, - tags { - title, - slug - } - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{eventId: event.id, title: "my event updated"} + ) - assert hd(json_response(res, 200)["errors"])["message"] == "You can't edit this event." + assert hd(res["errors"])["message"] == "You can't edit this event." end test "update_event/3 should check the user is the organizer also when it's changed", %{ @@ -727,29 +848,15 @@ defmodule Mobilizon.Web.Resolvers.EventTest do } do event = insert(:event) - mutation = """ - mutation { - updateEvent( - title: "my event updated", - event_id: #{event.id}, - organizer_actor_id: #{actor.id} - ) { - title, - uuid, - tags { - title, - slug - } - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{eventId: event.id, title: "my event updated", organizerActorId: actor.id} + ) - assert hd(json_response(res, 200)["errors"])["message"] == "You can't edit this event." + assert hd(res["errors"])["message"] == "You can't edit this event." end test "update_event/3 should check end time is after the beginning time", %{ @@ -759,29 +866,19 @@ defmodule Mobilizon.Web.Resolvers.EventTest do } do event = insert(:event, organizer_actor: actor) - mutation = """ - mutation { - updateEvent( - title: "my event updated", - ends_on: "#{Timex.shift(event.begins_on, hours: -2)}", - event_id: #{event.id} - ) { - title, - uuid, - tags { - title, - slug - } - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{ + eventId: event.id, + title: "my event updated", + endsOn: event.begins_on |> DateTime.add(3600 * -2) |> DateTime.to_iso8601() + } + ) - assert hd(json_response(res, 200)["errors"])["message"] == + assert hd(res["errors"])["message"] == ["ends_on cannot be set before begins_on"] end @@ -799,69 +896,41 @@ defmodule Mobilizon.Web.Resolvers.EventTest do begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() - mutation = """ - mutation { - updateEvent( - event_id: #{event.id}, - title: "my event updated", - description: "description updated", - begins_on: "#{begins_on}", - ends_on: "#{ends_on}", - status: TENTATIVE, - tags: ["tag1_updated", "tag2_updated"], - online_address: "toto@example.com", - phone_address: "0000000000", - category: "birthday", - options: { - maximumAttendeeCapacity: 30, - showRemainingAttendeeCapacity: true - }, - physical_address: { - street: "#{address.street}", - locality: "#{address.locality}" - } - ) { - id, - uuid, - url, - title, - description, - begins_on, - ends_on, - status, - tags { - title, - slug - }, - online_address, - phone_address, - category, - options { - maximumAttendeeCapacity, - showRemainingAttendeeCapacity - }, - physicalAddress { - url, - geom, - street - } - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{ + eventId: event.id, + title: "my event updated", + description: "description updated", + beginsOn: "#{begins_on}", + endsOn: "#{ends_on}", + status: "TENTATIVE", + tags: ["tag1_updated", "tag2_updated"], + onlineAddress: "toto@example.com", + phoneAddress: "0000000000", + category: "birthday", + options: %{ + maximumAttendeeCapacity: 30, + showRemainingAttendeeCapacity: true + }, + physicalAddress: %{ + street: "#{address.street}", + locality: "#{address.locality}" + } + } + ) - assert json_response(res, 200)["errors"] == nil + assert res["errors"] == nil - event_res = json_response(res, 200)["data"]["updateEvent"] + event_res = res["data"]["updateEvent"] assert event_res["title"] == "my event updated" assert event_res["description"] == "description updated" - assert event_res["begins_on"] == "#{begins_on}" - assert event_res["ends_on"] == "#{ends_on}" + assert event_res["beginsOn"] == "#{begins_on}" + assert event_res["endsOn"] == "#{ends_on}" assert event_res["status"] == "TENTATIVE" assert event_res["online_address"] == "toto@example.com" assert event_res["phone_address"] == "0000000000" @@ -920,212 +989,166 @@ defmodule Mobilizon.Web.Resolvers.EventTest do begins_on = event.begins_on - |> Timex.shift(hours: 3) + |> DateTime.add(3 * 3600) |> DateTime.truncate(:second) |> DateTime.to_iso8601() - mutation = """ - mutation { - updateEvent( - title: "my event updated", - description: "description updated", - begins_on: "#{begins_on}", - event_id: #{event.id}, - category: "birthday", - picture: { - media: { - name: "picture for my event", - alt: "A very sunny landscape", - file: "event.jpg", - actor_id: "#{actor.id}" - } - } - ) { - title, - uuid, - url, - beginsOn, - picture { - name, - url - } - } - } - """ - - map = %{ - "query" => mutation, - "event.jpg" => %Plug.Upload{ - path: "test/fixtures/picture.png", - filename: "event.jpg" - } - } - res = conn |> auth_conn(user) |> put_req_header("content-type", "multipart/form-data") - |> post("/api", map) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{ + eventId: event.id, + title: "my event updated", + description: "description updated", + beginsOn: "#{begins_on}", + category: "birthday", + picture: %{ + media: %{ + name: "picture for my event", + alt: "A very sunny landscape", + file: "event.jpg", + actorId: "#{actor.id}" + } + } + }, + uploads: %{ + "event.jpg" => %Plug.Upload{ + path: "test/fixtures/picture.png", + filename: "event.jpg" + } + } + ) - assert json_response(res, 200)["errors"] == nil - assert json_response(res, 200)["data"]["updateEvent"]["title"] == "my event updated" - assert json_response(res, 200)["data"]["updateEvent"]["uuid"] == event.uuid - assert json_response(res, 200)["data"]["updateEvent"]["url"] == event.url + assert res["errors"] == nil + assert res["data"]["updateEvent"]["title"] == "my event updated" + assert res["data"]["updateEvent"]["uuid"] == event.uuid + assert res["data"]["updateEvent"]["url"] == event.url - assert json_response(res, 200)["data"]["updateEvent"]["beginsOn"] == - DateTime.to_iso8601(event.begins_on |> Timex.shift(hours: 3)) + assert res["data"]["updateEvent"]["beginsOn"] == + event.begins_on |> DateTime.add(3 * 3600) |> DateTime.to_iso8601() - assert json_response(res, 200)["data"]["updateEvent"]["picture"]["name"] == + assert res["data"]["updateEvent"]["picture"]["name"] == "picture for my event" end - test "update_event/3 respects the draft status", %{conn: conn, actor: actor, user: user} do + @person_participations_query """ + query EventPersonParticipation($actorId: ID!, $eventId: ID!) { + person(id: $actorId) { + id + participations(eventId: $eventId) { + total + elements { + role + actor { + id + } + event { + id + } + } + } + } + } + """ + + test "respects the draft status", %{conn: conn, actor: actor, user: user} do event = insert(:event, organizer_actor: actor, draft: true) - mutation = """ - mutation { - updateEvent( - event_id: #{event.id}, - title: "my event updated but still draft" - ) { - draft, - title, - uuid - } - } - """ - res = conn |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - - assert json_response(res, 200)["data"]["updateEvent"]["draft"] == true - - query = """ - { - event(uuid: "#{event.uuid}") { - uuid, - draft - } - } - """ - - res = - conn - |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) - - assert hd(json_response(res, 200)["errors"])["message"] =~ "not found" - - query = """ - { - event(uuid: "#{event.uuid}") { - uuid, - draft - } - } - """ - - res = - conn - |> auth_conn(user) - |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) - - assert json_response(res, 200)["errors"] == nil - assert json_response(res, 200)["data"]["event"]["draft"] == true - - query = """ - { - person(id: "#{actor.id}") { - id, - participations(eventId: #{event.id}) { - elements { - id, - role, - actor { - id - }, - event { - id - } - } + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{ + eventId: event.id, + title: "my event updated but still draft", + draft: true } - } - } - """ + ) + + assert res["data"]["updateEvent"]["draft"] == true res = conn - |> auth_conn(user) - |> get("/api", AbsintheHelpers.query_skeleton(query, "person")) - - assert json_response(res, 200)["errors"] == nil - assert json_response(res, 200)["data"]["person"]["participations"]["elements"] == [] - - mutation = """ - mutation { - updateEvent( - event_id: #{event.id}, - title: "my event updated and no longer draft", - draft: false - ) { - draft, - title, - uuid - } - } - """ - - res = - conn - |> auth_conn(user) - |> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) - - assert json_response(res, 200)["data"]["updateEvent"]["draft"] == false - - query = """ - { - event(uuid: "#{event.uuid}") { - uuid, - draft - } - } - """ - - res = - conn - |> get("/api", AbsintheHelpers.query_skeleton(query, "event")) - - assert json_response(res, 200)["errors"] == nil - assert json_response(res, 200)["data"]["event"]["draft"] == false - - query = """ - { - person(id: "#{actor.id}") { - id, - participations(eventId: #{event.id}) { - elements { - role, - actor { - id - }, - event { - id - } - } + |> AbsintheHelpers.graphql_query( + query: @find_event_query, + variables: %{ + uuid: event.uuid } - } - } - """ + ) + + assert hd(res["errors"])["message"] =~ "not found" res = conn |> auth_conn(user) - |> get("/api", AbsintheHelpers.query_skeleton(query, "person")) + |> AbsintheHelpers.graphql_query( + query: @find_event_query, + variables: %{ + uuid: event.uuid + } + ) - assert json_response(res, 200)["errors"] == nil + assert res["errors"] == nil + assert res["data"]["event"]["draft"] == true - assert json_response(res, 200)["data"]["person"]["participations"]["elements"] == [ + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @person_participations_query, + variables: %{ + eventId: event.id, + actorId: actor.id + } + ) + + assert res["errors"] == nil + assert res["data"]["person"]["participations"]["elements"] == [] + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: %{ + eventId: event.id, + title: "my event updated and no longer draft", + draft: false + } + ) + + assert res["data"]["updateEvent"]["draft"] == false + + res = + conn + |> AbsintheHelpers.graphql_query( + query: @find_event_query, + variables: %{ + uuid: event.uuid + } + ) + + assert res["errors"] == nil + assert res["data"]["event"]["draft"] == false + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @person_participations_query, + variables: %{ + eventId: event.id, + actorId: actor.id + } + ) + + assert res["errors"] == nil + + assert res["data"]["person"]["participations"]["elements"] == [ %{ "actor" => %{"id" => to_string(actor.id)}, "event" => %{"id" => to_string(event.id)}, @@ -1133,7 +1156,98 @@ defmodule Mobilizon.Web.Resolvers.EventTest do } ] end + end + describe "update_event/3 on behalf of a group" do + test "should check the member has permission to update a group event", %{ + conn: conn + } do + %User{} = user = insert(:user) + %Actor{id: group_id} = group = insert(:group) + + %Actor{id: member_not_approved_actor_id} = + member_not_approved_actor = insert(:actor, user: user) + + insert(:member, parent: group, actor: member_not_approved_actor) + %Actor{id: member_actor_id} = member_actor = insert(:actor, user: user) + insert(:member, parent: group, actor: member_actor, role: :member) + %Actor{id: moderator_actor_id} = moderator_actor = insert(:actor, user: user) + insert(:member, parent: group, actor: moderator_actor, role: :moderator) + + %Actor{} = administrator_actor = insert(:actor, user: user) + insert(:member, parent: group, actor: administrator_actor, role: :administrator) + + %Actor{id: not_member_actor_id} = insert(:actor, user: user) + + %Event{} = + event = insert(:event, attributed_to: group, organizer_actor: administrator_actor) + + variables = + @variables + |> Map.put(:attributed_to_id, "#{group_id}") + |> Map.put(:eventId, to_string(event.id)) + + Users.update_user_default_actor(user.id, member_not_approved_actor_id) + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{member_not_approved_actor_id}") + ) + + assert res["data"]["updateEvent"] == nil + + assert hd(res["errors"])["message"] == + "This profile doesn't have permission to update an event on behalf of this group" + + Users.update_user_default_actor(user.id, not_member_actor_id) + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{not_member_actor_id}") + ) + + assert res["data"]["updateEvent"] == nil + + assert hd(res["errors"])["message"] == + "This profile doesn't have permission to update an event on behalf of this group" + + Users.update_user_default_actor(user.id, member_actor_id) + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{member_actor_id}") + ) + + assert res["data"]["updateEvent"] == nil + + assert hd(res["errors"])["message"] == + "This profile doesn't have permission to update an event on behalf of this group" + + Users.update_user_default_actor(user.id, moderator_actor_id) + + res = + conn + |> auth_conn(user) + |> AbsintheHelpers.graphql_query( + query: @update_event_mutation, + variables: Map.put(variables, :organizer_actor_id, "#{moderator_actor_id}") + ) + + assert res["errors"] == nil + assert res["data"]["updateEvent"] != nil + end + end + + describe "list_events/3" do @fetch_events_query """ query Events($page: Int, $limit: Int) { events(page: $page, limit: $limit) { @@ -1250,7 +1364,9 @@ defmodule Mobilizon.Web.Resolvers.EventTest do # assert json_response(res, 200)["errors"] |> hd |> Map.get("message") == # "Event with UUID #{event.uuid} not found" # end + end + describe "delete_event/3" do test "delete_event/3 deletes an event", %{conn: conn, user: user, actor: actor} do event = insert(:event, organizer_actor: actor) @@ -1393,7 +1509,9 @@ defmodule Mobilizon.Web.Resolvers.EventTest do "object" => %{"title" => event.title, "id" => to_string(event.id)} } end + end + describe "list_related_events/3" do test "list_related_events/3 should give related events", %{ conn: conn, actor: actor