defmodule Mobilizon.Web.Resolvers.EventTest do
use Mobilizon.Web.ConnCase
use Oban.Testing, repo: Mobilizon.Storage.Repo
import Mobilizon.Factory
alias Mobilizon.Actors.Actor
alias Mobilizon.{Events, Users}
alias Mobilizon.Events.Event
alias Mobilizon.Service.Workers
alias Mobilizon.Users.User
alias Mobilizon.GraphQL.AbsintheHelpers
import Swoosh.TestAssertions
@event %{
description: "some body",
title: "some title",
begins_on: DateTime.utc_now() |> DateTime.truncate(:second),
uuid: "b5126423-f1af-43e4-a923-002a03003ba4",
url: "some url",
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")
{:ok, conn: conn, actor: actor, user: user}
end
describe "Find an event" do
test "find_event/3 returns an event", context do
event =
@event
|> Map.put(:organizer_actor_id, context.actor.id)
{:ok, event} = Events.create_event(event)
res =
context.conn
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event.uuid})
assert res["data"]["event"]["uuid"] == to_string(event.uuid)
res =
context.conn
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: "bad uuid"})
assert [%{"message" => "Argument \"uuid\" has invalid value $uuid."}] = res["errors"]
res =
context.conn
|> AbsintheHelpers.graphql_query(
query: @find_event_query,
variables: %{uuid: "b5126423-f1af-43e4-a923-002a03003ba5"}
)
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!,
$description: String!,
$begins_on: DateTime!,
$ends_on: DateTime,
$status: EventStatus,
$visibility: EventVisibility,
$organizer_actor_id: ID!,
$attributed_to_id: ID,
$online_address: String,
$options: EventOptionsInput,
$draft: Boolean,
$language: String
$picture: MediaInput
$tags: [String]
$physicalAddress: AddressInput
$category: EventCategory
) {
createEvent(
title: $title,
description: $description,
begins_on: $begins_on,
ends_on: $ends_on,
status: $status,
visibility: $visibility,
organizer_actor_id: $organizer_actor_id,
attributed_to_id: $attributed_to_id,
online_address: $online_address,
options: $options,
draft: $draft,
picture: $picture
language: $language
physicalAddress: $physicalAddress
category: $category
tags: $tags
) {
id,
uuid,
title,
description,
begins_on,
ends_on,
status,
visibility,
organizer_actor {
id
},
attributed_to {
id
},
physicalAddress {
id,
url,
geom,
street
}
online_address,
phone_address,
category,
draft
language
options {
maximumAttendeeCapacity,
showRemainingAttendeeCapacity,
showEndTime
}
picture {
url
name
}
tags {
slug
title
}
}
}
"""
test "create_event/3 should check the organizer_actor_id is owned by the user", %{
conn: conn,
user: user
} do
another_actor = insert(:actor)
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{begins_on}",
organizer_actor_id: "#{another_actor.id}"
}
)
assert res["data"]["createEvent"] == nil
assert hd(res["errors"])["message"] ==
"Organizer profile is not owned by the user"
end
test "create_event/3 should check that end time is after start time", %{
conn: conn,
actor: actor,
user: user
} do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second)
ends_on = DateTime.add(begins_on, -2 * 3600)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{begins_on}",
ends_on: "#{ends_on}",
organizer_actor_id: "#{actor.id}"
}
)
assert hd(res["errors"])["message"] ==
["ends_on cannot be set before begins_on"]
end
test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do
begins_on = DateTime.utc_now()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.add(begins_on, 3600 * 24)}",
organizer_actor_id: "#{actor.id}"
}
)
assert res["data"]["createEvent"]["title"] == "come to my event"
id = String.to_integer(res["data"]["createEvent"]["id"])
uuid = res["data"]["createEvent"]["uuid"]
assert_enqueued(
worker: Workers.BuildSearch,
args: %{event_id: id, op: :insert_search_event}
)
assert_enqueued(
worker: Workers.EventDelayedNotificationWorker,
args: %{event_uuid: uuid, action: :notify_of_new_event},
scheduled_at: {DateTime.add(begins_on, 1800), delta: 5}
)
end
test "create_event/3 creates an event and escapes title", %{
conn: conn,
actor: actor,
user: user
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title:
"My Event title ",
description:
"My description
",
begins_on: DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601(),
organizer_actor_id: "#{actor.id}"
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["title"] ==
"My Event title
"
assert res["data"]["createEvent"]["description"] ==
"My description
"
{id, ""} = res["data"]["createEvent"]["id"] |> Integer.parse()
assert_enqueued(
worker: Workers.BuildSearch,
args: %{event_id: id, op: :insert_search_event}
)
end
test "create_event/3 creates an event as a draft", %{conn: conn, actor: actor, user: user} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.utc_now()}",
organizer_actor_id: "#{actor.id}",
draft: true
}
)
assert res["data"]["createEvent"]["title"] == "come to my event"
assert res["data"]["createEvent"]["draft"] == true
event_uuid = res["data"]["createEvent"]["uuid"]
event_id = res["data"]["createEvent"]["id"]
{event_id_int, ""} = Integer.parse(event_id)
refute_enqueued(
worker: Workers.BuildSearch,
args: %{event_id: event_id_int, op: :insert_search_event}
)
res =
conn
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert hd(res["errors"])["message"] =~ "not found"
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert res["errors"] == nil
assert res["data"]["event"]["draft"] == true
query = """
query Person($actor_id: ID!, $event_id: ID) {
person(id: $actor_id) {
id,
participations(eventId: $event_id) {
elements {
id,
role,
actor {
id
},
event {
id
}
}
}
}
}
"""
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: query,
variables: %{actor_id: actor.id, event_id: event_id}
)
assert res["errors"] == nil
assert res["data"]["person"]["participations"]["elements"] == []
end
test "create_event/3 creates an event as a draft for a group", %{
conn: conn,
actor: actor,
user: user
} do
%Actor{id: group_id} = group = insert(:group)
insert(:member, parent: group, actor: actor, role: :moderator)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.utc_now()}",
organizer_actor_id: "#{actor.id}",
attributed_to_id: group_id,
draft: true
}
)
assert res["data"]["createEvent"]["title"] == "come to my event"
assert res["data"]["createEvent"]["draft"] == true
assert res["data"]["createEvent"]["attributed_to"]["id"] == to_string(group_id)
event_uuid = res["data"]["createEvent"]["uuid"]
event_id = res["data"]["createEvent"]["id"]
refute_enqueued(
worker: Workers.BuildSearch,
args: %{event_id: String.to_integer(event_id), op: :insert_search_event}
)
res =
conn
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert hd(res["errors"])["message"] =~ "not found"
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert res["errors"] == nil
assert res["data"]["event"]["draft"] == true
end
test "create_event/3 creates an event with options", %{conn: conn, actor: actor, user: user} do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{begins_on}",
ends_on: "#{ends_on}",
status: "TENTATIVE",
visibility: "UNLISTED",
organizer_actor_id: "#{actor.id}",
online_address: "toto@example.com",
options: %{
maximumAttendeeCapacity: 30,
showRemainingAttendeeCapacity: true,
showEndTime: false
}
}
)
assert res["errors"] == nil
event = res["data"]["createEvent"]
assert event["title"] == "come to my event"
assert event["description"] == "it will be fine"
assert event["begins_on"] == begins_on
assert event["ends_on"] == ends_on
assert event["status"] == "TENTATIVE"
assert event["visibility"] == "UNLISTED"
assert event["organizer_actor"]["id"] == "#{actor.id}"
assert event["online_address"] == "toto@example.com"
assert event["options"]["maximumAttendeeCapacity"] == 30
assert event["options"]["showRemainingAttendeeCapacity"] == true
assert event["options"]["showEndTime"] == false
{event_id_int, ""} = Integer.parse(event["id"])
assert_enqueued(
worker: Workers.BuildSearch,
args: %{event_id: event_id_int, op: :insert_search_event}
)
end
test "create_event/3 creates an event an invalid options", %{
conn: conn,
actor: actor,
user: user
} do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{begins_on}",
organizer_actor_id: "#{actor.id}",
options: %{
maximumAttendeeCapacity: -5
}
}
)
assert hd(res["errors"])["message"] == %{
"maximum_attendee_capacity" => ["must be greater than or equal to 0"]
}
end
test "create_event/3 creates an event with tags", %{conn: conn, actor: actor, user: user} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "my event is referenced",
description: "with tags!",
begins_on:
"#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
organizer_actor_id: "#{actor.id}",
category: "PARTY",
tags: ["nicolas", "birthday", "bad tag"]
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["title"] == "my event is referenced"
assert res["data"]["createEvent"]["tags"] == [
%{"slug" => "nicolas", "title" => "nicolas"},
%{"slug" => "birthday", "title" => "birthday"},
%{"slug" => "bad-tag", "title" => "bad tag"}
]
assert res["data"]["createEvent"]["category"] == "PARTY"
end
test "create_event/3 creates an event with an address", %{
conn: conn,
actor: actor,
user: user
} do
address = %{street: "I am a street, please believe me", locality: "Where ever"}
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "my event is referenced",
description: "with tags!",
begins_on:
"#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
organizer_actor_id: "#{actor.id}",
category: "PARTY",
physicalAddress: %{
street: "#{address.street}",
locality: "#{address.locality}"
}
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["title"] == "my event is referenced"
assert res["data"]["createEvent"]["physicalAddress"]["street"] ==
address.street
address_url = res["data"]["createEvent"]["physicalAddress"]["url"]
address_id = res["data"]["createEvent"]["physicalAddress"]["id"]
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "my event is referenced",
description: "with tags!",
begins_on:
"#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
organizer_actor_id: "#{actor.id}",
category: "PARTY",
physicalAddress: %{
id: "#{address_id}"
}
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["title"] == "my event is referenced"
assert res["data"]["createEvent"]["physicalAddress"]["street"] ==
address.street
assert res["data"]["createEvent"]["physicalAddress"]["id"] ==
address_id
assert res["data"]["createEvent"]["physicalAddress"]["url"] ==
address_url
end
test "create_event/3 creates an event with an attached picture", %{
conn: conn,
actor: actor,
user: user
} do
map = %{
"query" => @create_event_mutation,
"variables" => %{
title: "come to my event",
description: "it will be fine",
begins_on:
"#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
organizer_actor_id: "#{actor.id}",
category: "PARTY",
picture: %{
media: %{
name: "picture for my event",
alt: "A very sunny landscape",
file: "event.jpg",
actor_id: actor.id
}
}
},
"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
)
|> json_response(200)
assert res["data"]["createEvent"]["title"] == "come to my event"
assert res["data"]["createEvent"]["picture"]["name"] ==
"picture for my event"
end
@upload_media_mutation """
mutation UploadMedia($name: String!, $alt: String, $file: Upload!) {
uploadMedia(
name: $name
alt: $alt
file: $file
) {
id
url
name
content_type
size
}
}
"""
test "create_event/3 creates an event with an picture ID", %{
conn: conn,
actor: actor,
user: user
} do
media = %{name: "my pic", alt: "represents something", file: "picture.png"}
map = %{
"query" => @upload_media_mutation,
"variables" => media,
media.file => %Plug.Upload{
path: "test/fixtures/picture.png",
filename: media.file
}
}
res =
conn
|> auth_conn(user)
|> put_req_header("content-type", "multipart/form-data")
|> post(
"/api",
map
)
|> json_response(200)
assert res["errors"] == nil
assert res["data"]["uploadMedia"]["name"] == media.name
media_id = res["data"]["uploadMedia"]["id"]
assert media_id !== "" and not is_nil(media_id)
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on:
"#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
organizer_actor_id: "#{actor.id}",
category: "PARTY",
picture: %{
media_id: "#{media_id}"
}
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["title"] == "come to my event"
assert res["data"]["createEvent"]["picture"]["name"] == media.name
assert res["data"]["createEvent"]["picture"]["url"]
end
test "create_event/3 creates an event with detected language", %{
conn: conn,
actor: %Actor{id: actor_id},
user: user
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "Come to my event",
description: "This should be long enough to get detected",
organizer_actor_id: actor_id,
begins_on: "2021-07-26T09:00:00Z"
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["language"] == "en"
end
test "create_event/3 creates an event with manually set language", %{
conn: conn,
actor: %Actor{id: actor_id},
user: user
} do
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "Come to my event",
description: "This should be long enough to get detected",
organizer_actor_id: actor_id,
begins_on: "2021-07-26T09:00:00Z",
language: "it"
}
)
assert res["errors"] == nil
assert res["data"]["createEvent"]["language"] == "it"
end
end
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)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: Map.put(variables, :organizer_actor_id, "#{member_not_approved_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, "#{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
describe "create_event/3 with special tags" do
test "same tags with different casing", %{conn: conn, actor: actor, user: user} do
begins_on = DateTime.utc_now()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.add(begins_on, 3600 * 24)}",
organizer_actor_id: "#{actor.id}",
tags: ["Hello", "hello"]
}
)
assert res["error"] == nil
assert res["data"]["createEvent"]["tags"] == [%{"slug" => "hello", "title" => "Hello"}]
end
test "too long tags", %{conn: conn, actor: actor, user: user} do
begins_on = DateTime.utc_now()
res =
conn
|> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event",
description:
"
it will be fine, what do you think?
#Detected
#ThisIsAVeryLongHashTagThatWillNotBeDetectedByTheParser