defmodule Mobilizon.GraphQL.Resolvers.DiscussionTest do use Mobilizon.Web.ConnCase import Mobilizon.Factory alias Mobilizon.Actors.Actor alias Mobilizon.Discussions alias Mobilizon.Discussions.{Comment, Discussion} alias Mobilizon.GraphQL.AbsintheHelpers @comment_text "What do you think?" @discussion_title "Hey, I'm a title!" setup %{conn: conn} do user = insert(:user) actor = insert(:actor, user: user) group = insert(:group) insert(:member, role: :member, parent: group, actor: actor) {:ok, conn: conn, actor: actor, user: user, group: group} end @discussion_fields_fragment """ fragment DiscussionFields on Discussion { id title slug lastComment { id text insertedAt updatedAt actor { id } } actor { id domain name preferredUsername } creator { id domain name preferredUsername } } """ describe "create a discussion" do @create_discussion_mutation """ mutation createDiscussion($title: String!, $actorId: ID!, $text: String!) { createDiscussion(title: $title, text: $text, actorId: $actorId) { ...DiscussionFields } } #{@discussion_fields_fragment} """ test "create_discussion/3 creates a discussion", %{ conn: conn, actor: actor, user: user, group: group } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_discussion_mutation, variables: %{text: @comment_text, actorId: group.id, title: @discussion_title} ) assert res["errors"] == nil assert res["data"]["createDiscussion"]["actor"]["id"] == to_string(group.id) assert res["data"]["createDiscussion"]["creator"]["id"] == to_string(actor.id) assert res["data"]["createDiscussion"]["title"] == @discussion_title assert res["data"]["createDiscussion"]["lastComment"]["text"] == @comment_text assert res["data"]["createDiscussion"]["lastComment"]["actor"]["id"] == to_string(actor.id) end test "create_discussion/3 doesn't work if the actor is not a member", %{ conn: conn, group: group } do user = insert(:user) insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_discussion_mutation, variables: %{text: @comment_text, actorId: group.id, title: @discussion_title} ) assert hd(res["errors"])["code"] == "unauthorized" end test "create_discussion/3 doesn't work if the actor is not an approved member", %{ conn: conn, group: group } do user = insert(:user) actor = insert(:actor, user: user) insert(:member, role: :invited, actor: actor, parent: group) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_discussion_mutation, variables: %{text: @comment_text, actorId: group.id, title: @discussion_title} ) assert hd(res["errors"])["code"] == "unauthorized" end test "create_discussion/3 doesn't work if the user isn't logged-in", %{ conn: conn, group: group } do res = conn |> AbsintheHelpers.graphql_query( query: @create_discussion_mutation, variables: %{text: @comment_text, actorId: group.id, title: @discussion_title} ) assert hd(res["errors"])["code"] == "unauthenticated" end end describe "reply to a discussion" do @reply_to_discussion_mutation """ mutation replyToDiscussion($discussionId: ID!, $text: String!) { replyToDiscussion(discussionId: $discussionId, text: $text) { ...DiscussionFields } } #{@discussion_fields_fragment} """ @reply_text "I agree with that." test "reply_to_discussion/3 replies to a discussion", %{ conn: conn, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) user = insert(:user) actor2 = insert(:actor, user: user) insert(:member, role: :member, parent: group, actor: actor2) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @reply_to_discussion_mutation, variables: %{text: @reply_text, discussionId: discussion_id} ) assert res["errors"] == nil assert res["data"]["replyToDiscussion"]["actor"]["id"] == to_string(group.id) assert res["data"]["replyToDiscussion"]["creator"]["id"] == to_string(actor.id) assert res["data"]["replyToDiscussion"]["lastComment"]["actor"]["id"] == to_string(actor2.id) assert res["data"]["replyToDiscussion"]["lastComment"]["text"] == @reply_text end end describe "Update a discussion" do @update_a_discussion_mutation """ mutation updateDiscussion($discussionId: ID!, $title: String!) { updateDiscussion(discussionId: $discussionId, title: $title) { ...DiscussionFields } } #{@discussion_fields_fragment} """ @updated_title "New title for discussion" test "update_a_discussion/3 updates a discussion as original creator", %{ conn: conn, user: user, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @update_a_discussion_mutation, variables: %{title: @updated_title, discussionId: discussion_id} ) assert res["errors"] == nil assert res["data"]["updateDiscussion"]["title"] == @updated_title end test "update_a_discussion/3 doesn't update a discussion if not member", %{ conn: conn, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) user = insert(:user) actor2 = insert(:actor, user: user) insert(:member, role: :invited, parent: group, actor: actor2) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @update_a_discussion_mutation, variables: %{title: @updated_title, discussionId: discussion_id} ) assert hd(res["errors"])["code"] == "unauthorized" end test "update_a_discussion/3 doesn't update a discussion if not logged in", %{ conn: conn, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) res = conn |> AbsintheHelpers.graphql_query( query: @update_a_discussion_mutation, variables: %{title: @updated_title, discussionId: discussion_id} ) assert hd(res["errors"])["code"] == "unauthenticated" end end describe "Delete a discussion" do @delete_discussion_mutation """ mutation deleteDiscussion($discussionId: ID!) { deleteDiscussion(discussionId: $discussionId) { id } } """ test "delete_discussion/3 deletes a discussion", %{ conn: conn, user: user, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @delete_discussion_mutation, variables: %{discussionId: discussion_id} ) assert res["errors"] == nil assert res["data"]["deleteDiscussion"]["id"] == to_string(discussion_id) assert nil == Discussions.get_discussion(discussion_id) end test "delete_discussion/3 doesn't delete a discussion if not member", %{ conn: conn, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) user = insert(:user) actor2 = insert(:actor, user: user) insert(:member, role: :invited, parent: group, actor: actor2) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @delete_discussion_mutation, variables: %{discussionId: discussion_id} ) assert hd(res["errors"])["code"] == "unauthorized" refute nil == Discussions.get_discussion(discussion_id) end test "delete_discussion/3 doesn't delete a discussion if not logged in", %{ conn: conn, actor: actor, group: group } do %Discussion{id: discussion_id} = insert_discussion(group, actor) res = conn |> AbsintheHelpers.graphql_query( query: @delete_discussion_mutation, variables: %{discussionId: discussion_id} ) assert hd(res["errors"])["code"] == "unauthenticated" refute nil == Discussions.get_discussion(discussion_id) end # test "create_comment/3 doesn't allow creating events if it's disabled", %{ # conn: conn, # actor: actor, # user: user, # event: event # } do # {:ok, %Event{options: %EventOptions{comment_moderation: :closed}}} = # Events.update_event(event, %{options: %{comment_moderation: :closed}}) # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query( # query: @create_comment_mutation, # variables: %{text: @comment_text, eventId: event.id} # ) # assert hd(res["errors"])["message"] == # "You don't have permission to do this" # end # test "create_comment/3 allows creating events if it's disabled but we're the organizer", %{ # conn: conn, # actor: actor, # user: user # } do # event = insert(:event, organizer_actor: actor, options: %{comment_moderation: :closed}) # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query( # query: @create_comment_mutation, # variables: %{text: @comment_text, eventId: event.id} # ) # assert is_nil(res["errors"]) # assert res["data"]["createComment"]["text"] == @comment_text # end # test "create_comment/3 requires that the user needs to be authenticated", %{ # conn: conn, # event: event # } do # actor = insert(:actor) # res = # conn # |> AbsintheHelpers.graphql_query( # query: @create_comment_mutation, # variables: %{text: @comment_text, eventId: event.id} # ) # assert hd(res["errors"])["message"] == # "You are not allowed to create a comment if not connected" # end # test "create_comment/3 creates a reply to a comment", %{ # conn: conn, # actor: actor, # user: user, # event: event # } do # comment = insert(:comment) # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query( # query: @create_comment_mutation, # variables: %{ # text: @comment_text, # eventId: event.id, # inReplyToCommentId: comment.id # } # ) # assert is_nil(res["errors"]) # assert res["data"]["createComment"]["text"] == @comment_text # uuid = res["data"]["createComment"]["uuid"] # assert res["data"]["createComment"]["inReplyToComment"]["id"] == # to_string(comment.id) # query = """ # query { # thread(id: #{comment.id}) { # text, # uuid # } # } # """ # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query(query: query, variables: %{}) # assert res["errors"] == nil # assert res["data"]["thread"] == [%{"uuid" => uuid, "text" => @comment_text}] # end # @delete_comment """ # mutation DeleteComment($commentId: ID!) { # deleteComment(commentId: $commentId) { # id, # deletedAt # } # } # """ # test "deletes a comment", %{conn: conn, user: user, actor: actor} do # comment = insert(:comment, actor: actor) # res = # conn # |> AbsintheHelpers.graphql_query( # query: @delete_comment, # variables: %{commentId: comment.id} # ) # assert hd(res["errors"])["message"] == # "You are not allowed to delete a comment if not connected" # # Change the current actor for user # actor2 = insert(:actor, user: user) # Mobilizon.Users.update_user_default_actor(user, actor2) # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query( # query: @delete_comment, # variables: %{commentId: comment.id} # ) # assert hd(res["errors"])["message"] == # "You cannot delete this comment" # Mobilizon.Users.update_user_default_actor(user, actor) # res = # conn # |> auth_conn(user) # |> AbsintheHelpers.graphql_query( # query: @delete_comment, # variables: %{commentId: comment.id} # ) # assert res["errors"] == nil # assert res["data"]["deleteComment"]["id"] == to_string(comment.id) # refute is_nil(res["data"]["deleteComment"]["deletedAt"]) # end # test "delete_comment/3 allows a comment being deleted by a moderator and creates a entry in actionLogs", # %{ # conn: conn, # user: _user, # actor: _actor # } do # user_moderator = insert(:user, role: :moderator) # actor_moderator = insert(:actor, user: user_moderator) # actor2 = insert(:actor) # comment = insert(:comment, actor: actor2) # res = # conn # |> auth_conn(user_moderator) # |> AbsintheHelpers.graphql_query( # query: @delete_comment, # variables: %{commentId: comment.id} # ) # assert res["data"]["deleteComment"]["id"] == to_string(comment.id) # query = """ # { # actionLogs { # action, # actor { # preferredUsername # }, # object { # ... on Report { # id, # status # }, # ... on ReportNote { # content # } # ... on Event { # id, # title # }, # ... on Comment { # id, # text # } # } # } # } # """ # res = # conn # |> auth_conn(user_moderator) # |> get("/api", AbsintheHelpers.query_skeleton(query, "actionLogs")) # refute json_response(res, 200)["errors"] # assert hd(json_response(res, 200)["data"]["actionLogs"]) == %{ # "action" => "COMMENT_DELETION", # "actor" => %{"preferredUsername" => actor_moderator.preferred_username}, # "object" => %{"text" => comment.text, "id" => to_string(comment.id)} # } # end end @spec insert_discussion(Actor.t(), Actor.t()) :: Discussion.t() defp insert_discussion(%Actor{type: :Group} = group, %Actor{} = actor) do %Comment{id: comment_id} = comment = insert(:comment) %Discussion{id: discussion_id} = discussion = insert(:discussion, creator: actor, actor: group) Discussions.update_comment(comment, %{discussion_id: discussion_id}) {:ok, %Discussion{} = discussion} = Discussions.update_discussion(discussion, %{last_comment_id: comment_id}) discussion end end