Merge branch 'validate-number-of-places' into 'master'

Validate number of places being a positive integer

Closes #286

See merge request framasoft/mobilizon!440
This commit is contained in:
Thomas Citharel 2020-06-05 11:52:33 +02:00
commit 09ad687403
4 changed files with 209 additions and 204 deletions

View file

@ -212,7 +212,6 @@ defmodule Mobilizon.Federation.ActivityPub do
else else
err -> err ->
Logger.error("Something went wrong while creating an activity") Logger.error("Something went wrong while creating an activity")
Logger.debug(inspect(err))
err err
end end
end end

View file

@ -2,24 +2,44 @@ defmodule Mobilizon.GraphQL.Helpers.Error do
@moduledoc """ @moduledoc """
Helper functions for Mobilizon.GraphQL Helper functions for Mobilizon.GraphQL
""" """
alias Ecto.Changeset
def handle_errors(fun) do def handle_errors(fun) do
fn source, args, info -> fn source, args, info ->
case Absinthe.Resolution.call(fun, source, args, info) do case Absinthe.Resolution.call(fun, source, args, info) do
{:error, %Ecto.Changeset{} = changeset} -> format_changeset(changeset) {:error, %Changeset{} = changeset} ->
val -> val format_changeset(changeset)
{:error, _, %Changeset{} = changeset} ->
format_changeset(changeset)
val ->
val
end end
end end
end end
def format_changeset(changeset) do def format_changeset(%Changeset{changes: changes} = changeset) do
# {:error, [email: {"has already been taken", []}]} # {:error, [email: {"has already been taken", []}]}
errors = errors =
changeset.errors Enum.reduce(changes, [], fn {_key, value}, acc ->
|> Enum.map(fn {key, {value, _context}} -> case value do
[message: "#{value}", details: key] %Changeset{} ->
{:error, errors} = format_changeset(value)
acc ++ errors
_ ->
acc
end
end) end)
errors = errors ++ Enum.map(changeset.errors, &transform_error/1)
{:error, errors} {:error, errors}
end end
defp transform_error({key, {value, _context}}) do
[message: "#{value}", details: key]
end
end end

View file

@ -66,6 +66,8 @@ defmodule Mobilizon.Events.EventOptions do
@doc false @doc false
@spec changeset(t, map) :: Ecto.Changeset.t() @spec changeset(t, map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = event_options, attrs) do def changeset(%__MODULE__{} = event_options, attrs) do
cast(event_options, attrs, @attrs) event_options
|> cast(attrs, @attrs)
|> validate_number(:maximum_attendee_capacity, greater_than_or_equal_to: 0)
end end
end end

View file

@ -29,6 +29,15 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
end end
describe "Event Resolver" do describe "Event Resolver" do
@find_event_query """
query Event($uuid: UUID!) {
event(uuid: $uuid) {
uuid,
draft
}
}
"""
test "find_event/3 returns an event", context do test "find_event/3 returns an event", context do
event = event =
@event @event
@ -36,36 +45,78 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
{:ok, event} = Events.create_event(event) {:ok, event} = Events.create_event(event)
query = """ res =
{ context.conn
event(uuid: "#{event.uuid}") { |> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event.uuid})
uuid,
} assert res["data"]["event"]["uuid"] == to_string(event.uuid)
}
"""
res = res =
context.conn context.conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "event")) |> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: "bad uuid"})
assert json_response(res, 200)["data"]["event"]["uuid"] == to_string(event.uuid) assert [%{"message" => "Argument \"uuid\" has invalid value $uuid."}] = res["errors"]
query = """
{
event(uuid: "bad uuid") {
uuid,
}
}
"""
res = res =
context.conn context.conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "event")) |> AbsintheHelpers.graphql_query(
query: @find_event_query,
variables: %{uuid: "b5126423-f1af-43e4-a923-002a03003ba5"}
)
assert [%{"message" => "Argument \"uuid\" has invalid value \"bad uuid\"."}] = assert [%{"message" => "Event with UUID b5126423-f1af-43e4-a923-002a03003ba5 not found"}] =
json_response(res, 200)["errors"] res["errors"]
end end
@create_event_mutation """
mutation CreateEvent(
$title: String!,
$description: String,
$begins_on: DateTime!,
$ends_on: DateTime,
$status: EventStatus,
$visibility: EventVisibility,
$organizer_actor_id: ID!,
$online_address: String,
$options: EventOptionsInput,
$draft: Boolean
) {
createEvent(
title: $title,
description: $description,
begins_on: $begins_on,
ends_on: $ends_on,
status: $status,
visibility: $visibility,
organizer_actor_id: $organizer_actor_id,
online_address: $online_address,
options: $options,
draft: $draft
) {
id,
uuid,
title,
description,
begins_on,
ends_on,
status,
visibility,
organizer_actor {
id
},
online_address,
phone_address,
category,
draft,
options {
maximumAttendeeCapacity,
showRemainingAttendeeCapacity,
showEndTime
}
}
}
"""
test "create_event/3 should check the organizer_actor_id is owned by the user", %{ test "create_event/3 should check the organizer_actor_id is owned by the user", %{
conn: conn, conn: conn,
user: user user: user
@ -74,29 +125,22 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
mutation = """
mutation {
createEvent(
title: "come to my event",
description: "it will be fine",
begins_on: "#{begins_on}",
organizer_actor_id: "#{another_actor.id}",
category: "birthday"
) {
title,
uuid
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> 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 json_response(res, 200)["data"]["createEvent"] == nil assert res["data"]["createEvent"] == nil
assert hd(json_response(res, 200)["errors"])["message"] == assert hd(res["errors"])["message"] ==
"Organizer actor id is not owned by the user" "Organizer actor id is not owned by the user"
end end
@ -106,60 +150,42 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
user: user user: user
} do } do
begins_on = DateTime.utc_now() |> DateTime.truncate(:second) begins_on = DateTime.utc_now() |> DateTime.truncate(:second)
ends_on = Timex.shift(begins_on, hours: -2) ends_on = DateTime.add(begins_on, -2 * 3600)
mutation = """
mutation {
createEvent(
title: "come to my event",
description: "it will be fine",
begins_on: "#{DateTime.to_iso8601(begins_on)}",
ends_on: "#{DateTime.to_iso8601(ends_on)}",
organizer_actor_id: "#{actor.id}",
category: "birthday"
) {
id,
title,
uuid
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> 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(json_response(res, 200)["errors"])["message"] == assert hd(res["errors"])["message"] ==
"ends_on cannot be set before begins_on" "ends_on cannot be set before begins_on"
end end
test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do test "create_event/3 creates an event", %{conn: conn, actor: actor, user: user} do
mutation = """
mutation {
createEvent(
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: "birthday"
) {
id,
title,
uuid
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> 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}"
}
)
assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event" assert res["data"]["createEvent"]["title"] == "come to my event"
{id, ""} = json_response(res, 200)["data"]["createEvent"]["id"] |> Integer.parse() {id, ""} = res["data"]["createEvent"]["id"] |> Integer.parse()
assert_enqueued( assert_enqueued(
worker: Workers.BuildSearch, worker: Workers.BuildSearch,
@ -172,27 +198,11 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
actor: actor, actor: actor,
user: user user: user
} do } do
mutation = """
mutation createEvent($title: String!, $description: String, $begins_on: DateTime, $organizer_actor_id: ID!) {
createEvent(
title: $title,
description: $description,
begins_on: $begins_on,
organizer_actor_id: $organizer_actor_id
) {
id,
title,
description,
uuid
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> AbsintheHelpers.graphql_query( |> AbsintheHelpers.graphql_query(
query: mutation, query: @create_event_mutation,
variables: %{ variables: %{
title: title:
"My Event title <img src=\"http://placekitten.com/g/200/300\" onclick=\"alert('aaa')\" >", "My Event title <img src=\"http://placekitten.com/g/200/300\" onclick=\"alert('aaa')\" >",
@ -218,36 +228,25 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
end end
test "create_event/3 creates an event as a draft", %{conn: conn, actor: actor, user: user} do test "create_event/3 creates an event as a draft", %{conn: conn, actor: actor, user: user} do
mutation = """
mutation {
createEvent(
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: "birthday",
draft: true
) {
title,
uuid,
id,
draft
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation)) |> 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 json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event" assert res["data"]["createEvent"]["title"] == "come to my event"
assert json_response(res, 200)["data"]["createEvent"]["draft"] == true assert res["data"]["createEvent"]["draft"] == true
event_uuid = json_response(res, 200)["data"]["createEvent"]["uuid"] event_uuid = res["data"]["createEvent"]["uuid"]
event_id = json_response(res, 200)["data"]["createEvent"]["id"] event_id = res["data"]["createEvent"]["id"]
{event_id_int, ""} = Integer.parse(event_id) {event_id_int, ""} = Integer.parse(event_id)
refute_enqueued( refute_enqueued(
@ -255,43 +254,25 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
args: %{event_id: event_id_int, op: :insert_search_event} args: %{event_id: event_id_int, op: :insert_search_event}
) )
query = """
{
event(uuid: "#{event_uuid}") {
uuid,
draft
}
}
"""
res = res =
conn conn
|> get("/api", AbsintheHelpers.query_skeleton(query, "event")) |> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert hd(json_response(res, 200)["errors"])["message"] =~ "not found" assert hd(res["errors"])["message"] =~ "not found"
query = """
{
event(uuid: "#{event_uuid}") {
uuid,
draft
}
}
"""
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "event")) |> AbsintheHelpers.graphql_query(query: @find_event_query, variables: %{uuid: event_uuid})
assert json_response(res, 200)["errors"] == nil assert res["errors"] == nil
assert json_response(res, 200)["data"]["event"]["draft"] == true assert res["data"]["event"]["draft"] == true
query = """ query = """
{ query Person($actor_id: ID!, $event_id: ID) {
person(id: "#{actor.id}") { person(id: $actor_id) {
id, id,
participations(eventId: #{event_id}) { participations(eventId: $event_id) {
id, id,
role, role,
actor { actor {
@ -308,65 +289,44 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
res = res =
conn conn
|> auth_conn(user) |> auth_conn(user)
|> get("/api", AbsintheHelpers.query_skeleton(query, "person")) |> AbsintheHelpers.graphql_query(
query: query,
variables: %{actor_id: actor.id, event_id: event_id}
)
assert json_response(res, 200)["errors"] == nil assert res["errors"] == nil
assert json_response(res, 200)["data"]["person"]["participations"] == [] assert res["data"]["person"]["participations"] == []
end end
test "create_event/3 creates an event with options", %{conn: conn, actor: actor, user: user} do 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() begins_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601() ends_on = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
mutation = """ res =
mutation { conn
createEvent( |> auth_conn(user)
|> AbsintheHelpers.graphql_query(
query: @create_event_mutation,
variables: %{
title: "come to my event", title: "come to my event",
description: "it will be fine", description: "it will be fine",
begins_on: "#{begins_on}", begins_on: "#{begins_on}",
ends_on: "#{ends_on}", ends_on: "#{ends_on}",
status: TENTATIVE, status: "TENTATIVE",
visibility: UNLISTED, visibility: "UNLISTED",
organizer_actor_id: "#{actor.id}", organizer_actor_id: "#{actor.id}",
online_address: "toto@example.com", online_address: "toto@example.com",
phone_address: "0000000000", options: %{
category: "super_category",
options: {
maximumAttendeeCapacity: 30, maximumAttendeeCapacity: 30,
showRemainingAttendeeCapacity: true, showRemainingAttendeeCapacity: true,
showEndTime: false showEndTime: false
} }
) {
id,
title,
description,
begins_on,
ends_on,
status,
visibility,
organizer_actor {
id
},
online_address,
phone_address,
category,
options {
maximumAttendeeCapacity,
showRemainingAttendeeCapacity,
showEndTime
} }
} )
}
"""
res = assert res["errors"] == nil
conn
|> auth_conn(user)
|> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
assert json_response(res, 200)["errors"] == nil event = res["data"]["createEvent"]
event = json_response(res, 200)["data"]["createEvent"]
assert event["title"] == "come to my event" assert event["title"] == "come to my event"
assert event["description"] == "it will be fine" assert event["description"] == "it will be fine"
@ -376,8 +336,6 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
assert event["visibility"] == "UNLISTED" assert event["visibility"] == "UNLISTED"
assert event["organizer_actor"]["id"] == "#{actor.id}" assert event["organizer_actor"]["id"] == "#{actor.id}"
assert event["online_address"] == "toto@example.com" assert event["online_address"] == "toto@example.com"
assert event["phone_address"] == "0000000000"
assert event["category"] == "super_category"
assert event["options"]["maximumAttendeeCapacity"] == 30 assert event["options"]["maximumAttendeeCapacity"] == 30
assert event["options"]["showRemainingAttendeeCapacity"] == true assert event["options"]["showRemainingAttendeeCapacity"] == true
assert event["options"]["showEndTime"] == false assert event["options"]["showEndTime"] == false
@ -389,6 +347,32 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
) )
end 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"] == "must be greater than or equal to %{number}"
end
test "create_event/3 creates an event with tags", %{conn: conn, actor: actor, user: user} do test "create_event/3 creates an event with tags", %{conn: conn, actor: actor, user: user} do
mutation = """ mutation = """
mutation { mutation {