diff --git a/config/dev.exs b/config/dev.exs
index 41fb0f73..b438a25b 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -50,6 +50,8 @@ config :mobilizon, MobilizonWeb.Endpoint,
# Do not include metadata nor timestamps in development logs
config :logger, :console, format: "[$level] $message\n", level: :debug
+config :mobilizon, Mobilizon.Service.Geospatial, service: Mobilizon.Service.Geospatial.Nominatim
+
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
config :phoenix, :stacktrace_depth, 20
diff --git a/js/src/components/Event/AddressAutoComplete.vue b/js/src/components/Event/AddressAutoComplete.vue
new file mode 100644
index 00000000..023ef796
--- /dev/null
+++ b/js/src/components/Event/AddressAutoComplete.vue
@@ -0,0 +1,53 @@
+
+
+ selected = option">
+
+
+ {{ option.description }}
+
+ {{ option.street }},
+ {{ option.locality }}
+
+
+
+
+
+
diff --git a/js/src/graphql/address.ts b/js/src/graphql/address.ts
new file mode 100644
index 00000000..0a16a98d
--- /dev/null
+++ b/js/src/graphql/address.ts
@@ -0,0 +1,18 @@
+import gql from 'graphql-tag';
+
+export const ADDRESS = gql`
+ query($query:String!) {
+ searchAddress(
+ query: $query
+ ) {
+ description,
+ geom,
+ floor,
+ street,
+ locality,
+ postalCode,
+ region,
+ country
+ }
+ }
+`;
diff --git a/js/src/graphql/event.ts b/js/src/graphql/event.ts
index a7174dcb..48ad5381 100644
--- a/js/src/graphql/event.ts
+++ b/js/src/graphql/event.ts
@@ -144,7 +144,8 @@ export const CREATE_EVENT = gql`
$category: String!,
$beginsOn: DateTime!,
$picture: PictureInput,
- $tags: [String]
+ $tags: [String],
+ $physicalAddress: AddressInput!
) {
createEvent(
title: $title,
@@ -153,7 +154,8 @@ export const CREATE_EVENT = gql`
organizerActorId: $organizerActorId,
category: $category,
picture: $picture,
- tags: $tags
+ tags: $tags,
+ physicalAddress: $physicalAddress
) {
id,
uuid,
diff --git a/js/src/types/address.model.ts b/js/src/types/address.model.ts
index 663ec425..fddab269 100644
--- a/js/src/types/address.model.ts
+++ b/js/src/types/address.model.ts
@@ -1,4 +1,5 @@
export interface IAddress {
+ id: number;
description: string;
floor: string;
street: string;
diff --git a/js/src/views/Event/Create.vue b/js/src/views/Event/Create.vue
index 4c0ce83e..856432c0 100644
--- a/js/src/views/Event/Create.vue
+++ b/js/src/views/Event/Create.vue
@@ -14,6 +14,8 @@
+
+
@@ -57,9 +59,10 @@ import DateTimePicker from '@/components/Event/DateTimePicker.vue';
import TagInput from '@/components/Event/TagInput.vue';
import { TAGS } from '@/graphql/tags';
import { ITag } from '@/types/tag.model';
+import AddressAutoComplete from '@/components/Event/AddressAutoComplete.vue';
@Component({
- components: { TagInput, DateTimePicker, PictureUpload, Editor },
+ components: { AddressAutoComplete, TagInput, DateTimePicker, PictureUpload, Editor },
apollo: {
loggedPerson: {
query: LOGGED_PERSON,
@@ -134,9 +137,13 @@ export default class CreateEvent extends Vue {
const obj = {
organizerActorId: this.loggedPerson.id,
beginsOn: this.event.beginsOn.toISOString(),
- tags: this.event.tags.map((tag: ITag) => tag.title),
+ tags: this.event.tags.map((tag: ITag) => tag.title)
};
- const res = Object.assign({}, this.event, obj);
+ let res = Object.assign({}, this.event, obj);
+
+ if (this.event.physicalAddress) {
+ delete this.event.physicalAddress['__typename'];
+ }
/**
* Transform picture files
diff --git a/lib/mix/tasks/mobilizon/toot.ex b/lib/mix/tasks/mobilizon/toot.ex
index e3ae9574..3f9371eb 100644
--- a/lib/mix/tasks/mobilizon/toot.ex
+++ b/lib/mix/tasks/mobilizon/toot.ex
@@ -11,10 +11,10 @@ defmodule Mix.Tasks.Mobilizon.Toot do
Mix.Task.run("app.start")
case MobilizonWeb.API.Comments.create_comment(from, content) do
- {:ok, _} ->
+ {:ok, _, _} ->
Mix.shell().info("Tooted")
- {:local_actor, _} ->
+ {:local_actor, _, _} ->
Mix.shell().error("Failed to toot.\nActor #{from} doesn't exist")
_ ->
diff --git a/lib/mobilizon/addresses/address.ex b/lib/mobilizon/addresses/address.ex
index 405a0af9..6dfcb434 100644
--- a/lib/mobilizon/addresses/address.ex
+++ b/lib/mobilizon/addresses/address.ex
@@ -6,6 +6,20 @@ defmodule Mobilizon.Addresses.Address do
alias Mobilizon.Addresses.Address
alias Mobilizon.Events.Event
# alias Mobilizon.Actors.Actor
+ @attrs [
+ :description,
+ :floor,
+ :geom,
+ :country,
+ :locality,
+ :region,
+ :postal_code,
+ :street,
+ :url
+ ]
+ @required [
+ :url
+ ]
schema "addresses" do
field(:country, :string)
@@ -16,8 +30,8 @@ defmodule Mobilizon.Addresses.Address do
field(:geom, Geo.PostGIS.Geometry)
field(:postal_code, :string)
field(:street, :string)
- has_one(:event, Event, foreign_key: :physical_address_id)
- # has_one(:group, Actor)
+ field(:url, :string)
+ has_many(:event, Event, foreign_key: :physical_address_id)
timestamps()
end
@@ -25,15 +39,15 @@ defmodule Mobilizon.Addresses.Address do
@doc false
def changeset(%Address{} = address, attrs) do
address
- |> cast(attrs, [
- :description,
- :floor,
- :geom,
- :country,
- :locality,
- :region,
- :postal_code,
- :street
- ])
+ |> cast(attrs, @attrs)
+ |> set_url()
+ |> validate_required(@required)
+ end
+
+ defp set_url(%Ecto.Changeset{changes: changes} = changeset) do
+ url =
+ Map.get(changes, :url, MobilizonWeb.Endpoint.url() <> "/address/#{Ecto.UUID.generate()}")
+
+ put_change(changeset, :url, url)
end
end
diff --git a/lib/mobilizon/addresses/addresses.ex b/lib/mobilizon/addresses/addresses.ex
index a0c8c002..0c2304f4 100644
--- a/lib/mobilizon/addresses/addresses.ex
+++ b/lib/mobilizon/addresses/addresses.ex
@@ -50,6 +50,21 @@ defmodule Mobilizon.Addresses do
"""
def get_address!(id), do: Repo.get!(Address, id)
+ @doc """
+ Gets a single address by it's url
+
+ ## Examples
+
+ iex> get_address_by_url("https://mobilizon.social/addresses/4572")
+ %Address{}
+
+ iex> get_address_by_url("https://mobilizon.social/addresses/099")
+ nil
+ """
+ def get_address_by_url(url) do
+ Repo.get_by(Address, url: url)
+ end
+
@doc """
Creates a address.
@@ -163,7 +178,7 @@ defmodule Mobilizon.Addresses do
We only look at the description for now, and eventually order by object distance
"""
@spec search_addresses(String.t(), list()) :: list(Address.t())
- def search_addresses(search, options) do
+ def search_addresses(search, options \\ []) do
limit = Keyword.get(options, :limit, 5)
query = from(a in Address, where: ilike(a.description, ^"%#{search}%"), limit: ^limit)
@@ -181,7 +196,7 @@ defmodule Mobilizon.Addresses do
do: from(a in query, where: ilike(a.country, ^"%#{country}%")),
else: query
- Repo.all(query)
+ if Keyword.get(options, :single, false) == true, do: Repo.one(query), else: Repo.all(query)
end
@doc """
diff --git a/lib/mobilizon/events/event.ex b/lib/mobilizon/events/event.ex
index 95005bb7..fe100b3e 100644
--- a/lib/mobilizon/events/event.ex
+++ b/lib/mobilizon/events/event.ex
@@ -84,9 +84,9 @@ defmodule Mobilizon.Events.Event do
:online_address,
:phone_address,
:uuid,
- :picture_id
+ :picture_id,
+ :physical_address_id
])
- |> cast_assoc(:physical_address)
|> validate_required([
:title,
:begins_on,
diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 31908182..7194dc89 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -382,7 +382,8 @@ defmodule Mobilizon.Events do
defp do_create_event(attrs) do
with {:ok, %Event{} = event} <- %Event{} |> Event.changeset(attrs) |> Repo.insert(),
- %Event{} = event <- event |> Repo.preload([:tags, :organizer_actor]),
+ %Event{} = event <-
+ event |> Repo.preload([:tags, :organizer_actor, :physical_address, :picture]),
{:has_tags, true, _} <- {:has_tags, Map.has_key?(attrs, "tags"), event} do
event
|> Ecto.Changeset.change()
@@ -513,8 +514,10 @@ defmodule Mobilizon.Events do
@doc """
Get an existing tag or create one
"""
- @spec get_or_create_tag(String.t()) :: {:ok, Tag.t()} | {:error, any()}
- def get_or_create_tag(title) do
+ @spec get_or_create_tag(map()) :: {:ok, Tag.t()} | {:error, any()}
+ def get_or_create_tag(tag) do
+ "#" <> title = tag["name"]
+
case Repo.get_by(Tag, title: title) do
%Tag{} = tag ->
{:ok, tag}
@@ -1223,9 +1226,13 @@ defmodule Mobilizon.Events do
"""
def create_comment(attrs \\ %{}) do
- %Comment{}
- |> Comment.changeset(attrs)
- |> Repo.insert()
+ with {:ok, %Comment{} = comment} <-
+ %Comment{}
+ |> Comment.changeset(attrs)
+ |> Repo.insert(),
+ %Comment{} = comment <- Repo.preload(comment, [:actor, :in_reply_to_comment]) do
+ {:ok, comment}
+ end
end
@doc """
diff --git a/lib/mobilizon_web/api/comments.ex b/lib/mobilizon_web/api/comments.ex
index 6680bd42..fbef7141 100644
--- a/lib/mobilizon_web/api/comments.ex
+++ b/lib/mobilizon_web/api/comments.ex
@@ -15,7 +15,8 @@ defmodule MobilizonWeb.API.Comments do
Creates a comment from an actor and a status
"""
- @spec create_comment(String.t(), String.t(), String.t()) :: {:ok, Activity.t()} | any()
+ @spec create_comment(String.t(), String.t(), String.t()) ::
+ {:ok, Activity.t(), Comment.t()} | any()
def create_comment(
from_username,
status,
diff --git a/lib/mobilizon_web/api/events.ex b/lib/mobilizon_web/api/events.ex
index aface5cf..4207dcd4 100644
--- a/lib/mobilizon_web/api/events.ex
+++ b/lib/mobilizon_web/api/events.ex
@@ -2,6 +2,7 @@ defmodule MobilizonWeb.API.Events do
@moduledoc """
API for Events
"""
+ alias Mobilizon.Addresses
alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
alias Mobilizon.Service.ActivityPub
@@ -11,7 +12,7 @@ defmodule MobilizonWeb.API.Events do
@doc """
Create an event
"""
- @spec create_event(map()) :: {:ok, Activity.t()} | any()
+ @spec create_event(map()) :: {:ok, Activity.t(), Event.t()} | any()
def create_event(
%{
title: title,
@@ -22,10 +23,9 @@ defmodule MobilizonWeb.API.Events do
tags: tags
} = args
) do
- require Logger
-
with %Actor{url: url} = actor <-
Actors.get_local_actor_with_everything(organizer_actor_id),
+ physical_address <- Map.get(args, :physical_address, nil),
title <- String.trim(title),
visibility <- Map.get(args, :visibility, :public),
picture <- Map.get(args, :picture, nil),
@@ -34,14 +34,12 @@ defmodule MobilizonWeb.API.Events do
event <-
ActivityPubUtils.make_event_data(
url,
- to,
+ %{to: to, cc: cc},
title,
content_html,
picture,
tags,
- cc,
- %{begins_on: begins_on},
- category
+ %{begins_on: begins_on, physical_address: physical_address, category: category}
) do
ActivityPub.create(%{
to: ["https://www.w3.org/ns/activitystreams#Public"],
@@ -51,4 +49,15 @@ defmodule MobilizonWeb.API.Events do
})
end
end
+
+ defp get_physical_address(address_id) when is_number(address_id),
+ do: Addresses.get_address!(address_id)
+
+ defp get_physical_address(address_id) when is_binary(address_id) do
+ with {address_id, ""} <- Integer.parse(address_id) do
+ get_physical_address(address_id)
+ end
+ end
+
+ defp get_physical_address(nil), do: nil
end
diff --git a/lib/mobilizon_web/api/groups.ex b/lib/mobilizon_web/api/groups.ex
index 7daf2aa7..8c6e8f64 100644
--- a/lib/mobilizon_web/api/groups.ex
+++ b/lib/mobilizon_web/api/groups.ex
@@ -11,7 +11,7 @@ defmodule MobilizonWeb.API.Groups do
@doc """
Create a group
"""
- @spec create_group(map()) :: {:ok, Activity.t()} | any()
+ @spec create_group(map()) :: {:ok, Activity.t(), Group.t()} | any()
def create_group(
%{
preferred_username: title,
diff --git a/lib/mobilizon_web/resolvers/address.ex b/lib/mobilizon_web/resolvers/address.ex
index 3dabf4c9..372cc03b 100644
--- a/lib/mobilizon_web/resolvers/address.ex
+++ b/lib/mobilizon_web/resolvers/address.ex
@@ -11,7 +11,7 @@ defmodule MobilizonWeb.Resolvers.Address do
Search an address
"""
@spec search(map(), map(), map()) :: {:ok, list(Address.t())}
- def search(_parent, %{query: query}, %{context: %{ip: ip}}) do
+ def search(_parent, %{query: query, page: _page, limit: _limit}, %{context: %{ip: ip}}) do
country = Geolix.lookup(ip) |> Map.get(:country, nil)
local_addresses = Task.async(fn -> Addresses.search_addresses(query, country: country) end)
diff --git a/lib/mobilizon_web/resolvers/comment.ex b/lib/mobilizon_web/resolvers/comment.ex
index 09d866bf..c167b898 100644
--- a/lib/mobilizon_web/resolvers/comment.ex
+++ b/lib/mobilizon_web/resolvers/comment.ex
@@ -11,14 +11,10 @@ defmodule MobilizonWeb.Resolvers.Comment do
def create_comment(_parent, %{text: comment, actor_username: username}, %{
context: %{current_user: %User{} = _user}
}) do
- with {:ok, %Activity{data: %{"object" => %{"type" => "Note"} = object}}} <-
+ with {:ok, %Activity{data: %{"object" => %{"type" => "Note"} = _object}},
+ %Comment{} = comment} <-
Comments.create_comment(username, comment) do
- {:ok,
- %Comment{
- text: object["content"],
- url: object["id"],
- uuid: object["uuid"]
- }}
+ {:ok, comment}
end
end
diff --git a/lib/mobilizon_web/resolvers/event.ex b/lib/mobilizon_web/resolvers/event.ex
index 339fbbdb..d3155bed 100644
--- a/lib/mobilizon_web/resolvers/event.ex
+++ b/lib/mobilizon_web/resolvers/event.ex
@@ -3,6 +3,8 @@ defmodule MobilizonWeb.Resolvers.Event do
Handles the event-related GraphQL calls
"""
alias Mobilizon.Activity
+ alias Mobilizon.Addresses
+ alias Mobilizon.Addresses.Address
alias Mobilizon.Events
alias Mobilizon.Events.{Event, Participant}
alias Mobilizon.Media.Picture
@@ -190,25 +192,10 @@ defmodule MobilizonWeb.Resolvers.Event do
"""
def create_event(_parent, args, %{context: %{current_user: _user}} = _resolution) do
with {:ok, args} <- save_attached_picture(args),
- {:ok, %Activity{data: %{"object" => %{"type" => "Event"} = object}}} <-
+ {:ok, args} <- save_physical_address(args),
+ {:ok, %Activity{data: %{"object" => %{"type" => "Event"} = _object}}, %Event{} = event} <-
MobilizonWeb.API.Events.create_event(args) do
- res = %{
- title: object["name"],
- description: object["content"],
- uuid: object["uuid"],
- url: object["id"]
- }
-
- res =
- if Map.has_key?(object, "attachment"),
- do:
- Map.put(res, :picture, %{
- name: object["attachment"] |> hd() |> Map.get("name"),
- url: object["attachment"] |> hd() |> Map.get("url") |> hd() |> Map.get("href")
- }),
- else: res
-
- {:ok, res}
+ {:ok, event}
end
end
@@ -237,6 +224,25 @@ defmodule MobilizonWeb.Resolvers.Event do
@spec save_attached_picture(map()) :: {:ok, map()}
defp save_attached_picture(args), do: {:ok, args}
+ @spec save_physical_address(map()) :: {:ok, map()}
+ defp save_physical_address(%{physical_address: %{url: physical_address_url}} = args) do
+ with %Address{} = address <- Addresses.get_address_by_url(physical_address_url),
+ args <- Map.put(args, :physical_address, address) do
+ {:ok, args}
+ end
+ end
+
+ # @spec save_physical_address(map()) :: {:ok, map()}
+ # defp save_physical_address(%{physical_address: address} = args) do
+ # with {:ok, %Address{} = address} <- Addresses.create_address(address),
+ # args <- Map.put(args, :physical_address, address) do
+ # {:ok, args}
+ # end
+ # end
+
+ @spec save_physical_address(map()) :: {:ok, map()}
+ defp save_physical_address(args), do: {:ok, args}
+
@doc """
Delete an event
"""
diff --git a/lib/mobilizon_web/resolvers/group.ex b/lib/mobilizon_web/resolvers/group.ex
index e24f4ae3..96b4214e 100644
--- a/lib/mobilizon_web/resolvers/group.ex
+++ b/lib/mobilizon_web/resolvers/group.ex
@@ -47,20 +47,15 @@ defmodule MobilizonWeb.Resolvers.Group do
:ok,
%Activity{
data: %{
- "object" => %{"type" => "Group"} = object
+ "object" => %{"type" => "Group"} = _object
}
- }
+ },
+ %Actor{} = group
} <-
MobilizonWeb.API.Groups.create_group(args) do
{
:ok,
- %Actor{
- preferred_username: object["preferredUsername"],
- summary: object["summary"],
- type: :Group,
- # uuid: object["uuid"],
- url: object["id"]
- }
+ group
}
end
diff --git a/lib/mobilizon_web/schema/address.ex b/lib/mobilizon_web/schema/address.ex
index acbdeed7..2bbbb0be 100644
--- a/lib/mobilizon_web/schema/address.ex
+++ b/lib/mobilizon_web/schema/address.ex
@@ -14,6 +14,7 @@ defmodule MobilizonWeb.Schema.AddressType do
field(:region, :string)
field(:country, :string)
field(:description, :string)
+ field(:url, :string)
end
object :phone_address do
@@ -26,10 +27,25 @@ defmodule MobilizonWeb.Schema.AddressType do
field(:info, :string)
end
+ input_object :address_input do
+ # Either a full picture object
+ field(:geom, :point, description: "The geocoordinates for the point where this address is")
+ field(:floor, :string, description: "The floor this event is at")
+ field(:street, :string, description: "The address's street name (with number)")
+ field(:locality, :string, description: "The address's locality")
+ field(:postal_code, :string)
+ field(:region, :string)
+ field(:country, :string)
+ field(:description, :string)
+ field(:url, :string)
+ end
+
object :address_queries do
@desc "Search for an address"
field :search_address, type: list_of(:address) do
arg(:query, non_null(:string))
+ arg(:page, :integer, default_value: 1)
+ arg(:limit, :integer, default_value: 10)
resolve(&Resolvers.Address.search/3)
end
diff --git a/lib/mobilizon_web/schema/event.ex b/lib/mobilizon_web/schema/event.ex
index 12285a7a..aff8bc83 100644
--- a/lib/mobilizon_web/schema/event.ex
+++ b/lib/mobilizon_web/schema/event.ex
@@ -22,7 +22,7 @@ defmodule MobilizonWeb.Schema.EventType do
field(:begins_on, :datetime, description: "Datetime for when the event begins")
field(:ends_on, :datetime, description: "Datetime for when the event ends")
field(:status, :event_status, description: "Status of the event")
- field(:visibility, :event_visibility, description: "The event's visibility")
+ field(:visibility, :event_visibility, description: "The event's visibility")
field(:picture, :picture,
description: "The event's picture",
@@ -132,6 +132,7 @@ defmodule MobilizonWeb.Schema.EventType do
arg(:phone_address, :string)
arg(:organizer_actor_id, non_null(:id))
arg(:category, non_null(:string))
+ arg(:physical_address, :address_input)
resolve(&Event.create_event/3)
end
diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/service/activity_pub/activity_pub.ex
index 0efdc5dc..483a7a14 100644
--- a/lib/service/activity_pub/activity_pub.ex
+++ b/lib/service/activity_pub/activity_pub.ex
@@ -70,10 +70,11 @@ defmodule Mobilizon.Service.ActivityPub do
def fetch_object_from_url(url) do
Logger.info("Fetching object from url #{url}")
- with true <- String.starts_with?(url, "http"),
- nil <- Events.get_event_by_url(url),
- nil <- Events.get_comment_from_url(url),
- {:error, :actor_not_found} <- Actors.get_actor_by_url(url),
+ with {:not_http, true} <- {:not_http, String.starts_with?(url, "http")},
+ {:existing_event, nil} <- {:existing_event, Events.get_event_by_url(url)},
+ {:existing_comment, nil} <- {:existing_comment, Events.get_comment_from_url(url)},
+ {:existing_actor, {:error, :actor_not_found}} <-
+ {:existing_actor, Actors.get_actor_by_url(url)},
{:ok, %{body: body, status_code: code}} when code in 200..299 <-
HTTPoison.get(
url,
@@ -90,25 +91,32 @@ defmodule Mobilizon.Service.ActivityPub do
"actor" => data["attributedTo"],
"object" => data
},
- {:ok, activity} <- Transmogrifier.handle_incoming(params) do
+ {:ok, _activity, %{url: object_url} = _object} <- Transmogrifier.handle_incoming(params) do
case data["type"] do
"Event" ->
- {:ok, Events.get_event_by_url!(activity.data["object"]["id"])}
+ {:ok, Events.get_event_by_url!(object_url)}
"Note" ->
- {:ok, Events.get_comment_full_from_url!(activity.data["object"]["id"])}
+ {:ok, Events.get_comment_full_from_url!(object_url)}
"Actor" ->
- {:ok, Actors.get_actor_by_url!(activity.data["object"]["id"], true)}
+ {:ok, Actors.get_actor_by_url!(object_url, true)}
other ->
{:error, other}
end
else
- %Event{url: event_url} -> {:ok, Events.get_event_by_url!(event_url)}
- %Comment{url: comment_url} -> {:ok, Events.get_comment_full_from_url!(comment_url)}
- %Actor{url: actor_url} -> {:ok, Actors.get_actor_by_url!(actor_url, true)}
- e -> {:error, e}
+ {:existing_event, %Event{url: event_url}} ->
+ {:ok, Events.get_event_by_url!(event_url)}
+
+ {:existing_comment, %Comment{url: comment_url}} ->
+ {:ok, Events.get_comment_full_from_url!(comment_url)}
+
+ {:existing_actor, %Actor{url: actor_url}} ->
+ {:ok, Actors.get_actor_by_url!(actor_url, true)}
+
+ e ->
+ {:error, e}
end
end
@@ -130,10 +138,10 @@ defmodule Mobilizon.Service.ActivityPub do
additional
),
:ok <- Logger.debug(inspect(create_data)),
- {:ok, activity, _object} <- insert(create_data, local),
+ {:ok, activity, object} <- insert(create_data, local),
:ok <- maybe_federate(activity) do
# {:ok, actor} <- Actors.increase_event_count(actor) do
- {:ok, activity}
+ {:ok, activity, object}
else
err ->
Logger.error("Something went wrong")
@@ -147,9 +155,9 @@ defmodule Mobilizon.Service.ActivityPub do
local = !(params[:local] == false)
with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
end
end
@@ -164,9 +172,9 @@ defmodule Mobilizon.Service.ActivityPub do
"actor" => actor,
"object" => object
},
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
end
end
@@ -179,7 +187,7 @@ defmodule Mobilizon.Service.ActivityPub do
# ) do
# with nil <- get_existing_like(url, object),
# like_data <- make_like_data(user, object, activity_id),
- # {:ok, activity, _object} <- insert(like_data, local),
+ # {:ok, activity, object} <- insert(like_data, local),
# {:ok, object} <- add_like_to_object(activity, object),
# :ok <- maybe_federate(activity) do
# {:ok, activity, object}
@@ -215,7 +223,7 @@ defmodule Mobilizon.Service.ActivityPub do
# ) do
# #with true <- is_public?(object),
# with announce_data <- make_announce_data(actor, object, activity_id),
- # {:ok, activity, _object} <- insert(announce_data, local),
+ # {:ok, activity, object} <- insert(announce_data, local),
# # {:ok, object} <- add_announce_to_object(activity, object),
# :ok <- maybe_federate(activity) do
# {:ok, activity, object}
@@ -250,9 +258,9 @@ defmodule Mobilizon.Service.ActivityPub do
activity_follow_id <-
activity_id || "#{MobilizonWeb.Endpoint.url()}/follow/#{follow_id}/activity",
data <- make_follow_data(followed, follower, activity_follow_id),
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
else
{err, _} when err in [:already_following, :suspended] ->
{:error, err}
@@ -269,9 +277,9 @@ defmodule Mobilizon.Service.ActivityPub do
data <- make_follow_data(followed, follower, follow_id),
{:ok, follow_activity, _object} <- insert(data, local),
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
- {:ok, activity, _object} <- insert(unfollow_data, local),
+ {:ok, activity, object} <- insert(unfollow_data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
else
err ->
Logger.error(inspect(err))
@@ -290,9 +298,9 @@ defmodule Mobilizon.Service.ActivityPub do
}
with {:ok, _} <- Events.delete_event(event),
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
end
end
@@ -305,9 +313,9 @@ defmodule Mobilizon.Service.ActivityPub do
}
with {:ok, _} <- Events.delete_comment(comment),
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
end
end
@@ -320,9 +328,9 @@ defmodule Mobilizon.Service.ActivityPub do
}
with {:ok, _} <- Actors.delete_actor(actor),
- {:ok, activity, _object} <- insert(data, local),
+ {:ok, activity, object} <- insert(data, local),
:ok <- maybe_federate(activity) do
- {:ok, activity}
+ {:ok, activity, object}
end
end
diff --git a/lib/service/activity_pub/converters/address.ex b/lib/service/activity_pub/converters/address.ex
new file mode 100644
index 00000000..d6d0cc1c
--- /dev/null
+++ b/lib/service/activity_pub/converters/address.ex
@@ -0,0 +1,58 @@
+defmodule Mobilizon.Service.ActivityPub.Converters.Address do
+ @moduledoc """
+ Flag converter
+
+ This module allows to convert reports from ActivityStream format to our own internal one, and back.
+
+ Note: Reports are named Flag in AS.
+ """
+ alias Mobilizon.Addresses.Address, as: AddressModel
+ alias Mobilizon.Service.ActivityPub.Converter
+
+ @behaviour Converter
+
+ @doc """
+ Converts an AP object data to our internal data structure
+ """
+ @impl Converter
+ @spec as_to_model_data(map()) :: map()
+ def as_to_model_data(object) do
+ res = %{
+ "description" => object["name"],
+ "url" => object["url"]
+ }
+
+ res =
+ if is_nil(object["address"]) do
+ res
+ else
+ Map.merge(res, %{
+ "country" => object["address"]["addressCountry"],
+ "postal_code" => object["address"]["postalCode"],
+ "region" => object["address"]["addressRegion"],
+ "street" => object["address"]["streetAddress"],
+ "locality" => object["address"]["addressLocality"]
+ })
+ end
+
+ if is_nil(object["geo"]) do
+ res
+ else
+ geo = %Geo.Point{
+ coordinates: {object["geo"]["latitude"], object["geo"]["longitude"]},
+ srid: 4326
+ }
+
+ Map.put(res, "geom", geo)
+ end
+ end
+
+ @doc """
+ Convert an event struct to an ActivityStream representation
+ """
+ @impl Converter
+ @spec model_to_as(AddressModel.t()) :: map()
+ def model_to_as(%AddressModel{} = _address) do
+ nil
+ end
+end
diff --git a/lib/service/activity_pub/converters/event.ex b/lib/service/activity_pub/converters/event.ex
index 64021611..1c6a6450 100644
--- a/lib/service/activity_pub/converters/event.ex
+++ b/lib/service/activity_pub/converters/event.ex
@@ -12,19 +12,28 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
alias Mobilizon.Service.ActivityPub.Converter
alias Mobilizon.Events
alias Mobilizon.Events.Tag
+ alias Mobilizon.Addresses
+ alias Mobilizon.Addresses.Address
@behaviour Converter
+ require Logger
+
@doc """
Converts an AP object data to our internal data structure
"""
@impl Converter
@spec as_to_model_data(map()) :: map()
def as_to_model_data(object) do
- with {:ok, %Actor{id: actor_id}} <- Actors.get_actor_by_url(object["actor"]),
- tags <- fetch_tags(object["tag"]) do
+ Logger.debug("event as_to_model_data")
+
+ with {:actor, {:ok, %Actor{id: actor_id}}} <-
+ {:actor, Actors.get_actor_by_url(object["actor"])},
+ {:address, address_id} <-
+ {:address, get_address(object["location"])},
+ {:tags, tags} <- {:tags, fetch_tags(object["tag"])} do
picture_id =
- with true <- Map.has_key?(object, "attachment"),
+ with true <- Map.has_key?(object, "attachment") && length(object["attachment"]) > 0,
%Picture{id: picture_id} <-
Media.get_picture_by_url(
object["attachment"]
@@ -38,27 +47,64 @@ defmodule Mobilizon.Service.ActivityPub.Converters.Event do
_ -> nil
end
- %{
- "title" => object["name"],
- "description" => object["content"],
- "organizer_actor_id" => actor_id,
- "picture_id" => picture_id,
- "begins_on" => object["begins_on"],
- "category" => object["category"],
- "url" => object["id"],
- "uuid" => object["uuid"],
- "tags" => tags
- }
+ {:ok,
+ %{
+ "title" => object["name"],
+ "description" => object["content"],
+ "organizer_actor_id" => actor_id,
+ "picture_id" => picture_id,
+ "begins_on" => object["startTime"],
+ "category" => object["category"],
+ "url" => object["id"],
+ "uuid" => object["uuid"],
+ "tags" => tags,
+ "physical_address_id" => address_id
+ }}
+ else
+ err ->
+ {:error, err}
+ end
+ end
+
+ defp get_address(%{"id" => url} = map) when is_map(map) and is_binary(url) do
+ Logger.debug("Address with an URL, let's check against our own database")
+
+ case Addresses.get_address_by_url(url) do
+ %Address{id: address_id} ->
+ address_id
+
+ _ ->
+ Logger.debug("not in our database, let's try to create it")
+ map = Map.put(map, "url", map["id"])
+ do_get_address(map)
+ end
+ end
+
+ defp get_address(map) when is_map(map) do
+ do_get_address(map)
+ end
+
+ defp get_address(nil), do: nil
+
+ defp do_get_address(map) do
+ map = Mobilizon.Service.ActivityPub.Converters.Address.as_to_model_data(map)
+
+ case Addresses.create_address(map) do
+ {:ok, %Address{id: address_id}} ->
+ address_id
+
+ _ ->
+ nil
end
end
defp fetch_tags(tags) do
Enum.reduce(tags, [], fn tag, acc ->
- case Events.get_or_create_tag(tag) do
- {:ok, %Tag{} = tag} ->
- acc ++ [tag]
-
- _ ->
+ with true <- tag["type"] == "Hashtag",
+ {:ok, %Tag{} = tag} <- Events.get_or_create_tag(tag) do
+ acc ++ [tag]
+ else
+ _err ->
acc
end
end)
diff --git a/lib/service/activity_pub/transmogrifier.ex b/lib/service/activity_pub/transmogrifier.ex
index 5f4658b3..d2022b78 100644
--- a/lib/service/activity_pub/transmogrifier.ex
+++ b/lib/service/activity_pub/transmogrifier.ex
@@ -132,9 +132,6 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
end
end
- # TODO: validate those with a Ecto scheme
- # - tags
- # - emoji
def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
Logger.info("Handle incoming to create notes")
@@ -159,15 +156,39 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
end
end
+ def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Event"} = object} = data) do
+ Logger.info("Handle incoming to create event")
+
+ with {:ok, %Actor{} = actor} <- Actors.get_or_fetch_by_url(data["actor"]) do
+ Logger.debug("found actor")
+ Logger.debug(inspect(actor))
+
+ params = %{
+ to: data["to"],
+ object: object |> fix_object,
+ actor: actor,
+ local: false,
+ published: data["published"],
+ additional:
+ Map.take(data, [
+ "cc",
+ "id"
+ ])
+ }
+
+ ActivityPub.create(params)
+ end
+ end
+
def handle_incoming(
%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data
) do
with {:ok, %Actor{} = followed} <- Actors.get_or_fetch_by_url(followed, true),
{:ok, %Actor{} = follower} <- Actors.get_or_fetch_by_url(follower),
- {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
+ {:ok, activity, object} <- ActivityPub.follow(follower, followed, id, false) do
ActivityPub.accept(%{to: [follower.url], actor: followed.url, object: data, local: true})
- {:ok, activity}
+ {:ok, activity, object}
else
e ->
Logger.error("Unable to handle Follow activity")
@@ -257,9 +278,9 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
) do
with {:ok, %Actor{domain: nil} = followed} <- Actors.get_actor_by_url(followed),
{:ok, %Actor{} = follower} <- Actors.get_actor_by_url(follower),
- {:ok, activity} <- ActivityPub.unfollow(followed, follower, id, false) do
+ {:ok, activity, object} <- ActivityPub.unfollow(followed, follower, id, false) do
Actor.unfollow(follower, followed)
- {:ok, activity}
+ {:ok, activity, object}
else
e ->
Logger.error(inspect(e))
@@ -282,11 +303,11 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
{:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id),
# TODO : Validate that DELETE comes indeed form right domain (see above)
# :ok <- contain_origin(actor_url, object.data),
- {:ok, activity} <- ActivityPub.delete(object, false) do
- {:ok, activity}
+ {:ok, activity, object} <- ActivityPub.delete(object, false) do
+ {:ok, activity, object}
else
e ->
- Logger.debug(inspect(e))
+ Logger.error(inspect(e))
:error
end
end
diff --git a/lib/service/activity_pub/utils.ex b/lib/service/activity_pub/utils.ex
index 8f1b9b5c..59c0b1c4 100644
--- a/lib/service/activity_pub/utils.ex
+++ b/lib/service/activity_pub/utils.ex
@@ -11,6 +11,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
"""
alias Mobilizon.Repo
+ alias Mobilizon.Addresses.Address
alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.Event
@@ -122,7 +123,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
"""
def insert_full_object(%{"object" => %{"type" => "Event"} = object_data})
when is_map(object_data) do
- with object_data <-
+ with {:ok, object_data} <-
Converters.Event.as_to_model_data(object_data),
{:ok, %Event{} = event} <- Events.create_event(object_data) do
{:ok, event}
@@ -260,26 +261,21 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
"""
@spec make_event_data(
String.t(),
- String.t(),
+ map(),
String.t(),
String.t(),
map(),
list(),
- list(),
- map(),
- String.t()
+ map()
) :: map()
def make_event_data(
actor,
- to,
+ %{to: to, cc: cc} = _audience,
title,
content_html,
picture \\ nil,
tags \\ [],
- # _cw \\ nil,
- cc \\ [],
- metadata \\ %{},
- category \\ ""
+ metadata \\ %{}
) do
Logger.debug("Making event data")
uuid = Ecto.UUID.generate()
@@ -287,21 +283,58 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
res = %{
"type" => "Event",
"to" => to,
- "cc" => cc,
+ "cc" => cc || [],
"content" => content_html,
"name" => title,
- # "summary" => cw,
- "begins_on" => metadata.begins_on,
- "category" => category,
+ "startTime" => metadata.begins_on,
+ "category" => metadata.category,
"actor" => actor,
"id" => Routes.page_url(Endpoint, :event, uuid),
"uuid" => uuid,
- "tag" => tags |> Enum.uniq()
+ "tag" =>
+ tags |> Enum.uniq() |> Enum.map(fn tag -> %{"type" => "Hashtag", "name" => "##{tag}"} end)
}
+ res =
+ if is_nil(metadata.physical_address),
+ do: res,
+ else: Map.put(res, "location", make_address_data(metadata.physical_address))
+
if is_nil(picture), do: res, else: Map.put(res, "attachment", [make_picture_data(picture)])
end
+ def make_address_data(%Address{} = address) do
+ res = %{
+ "type" => "Place",
+ "name" => address.description,
+ "id" => address.url,
+ "address" => %{
+ "type" => "PostalAddress",
+ "streetAddress" => address.street,
+ "postalCode" => address.postal_code,
+ "addressLocality" => address.locality,
+ "addressRegion" => address.region,
+ "addressCountry" => address.country
+ }
+ }
+
+ if is_nil(address.geom) do
+ res
+ else
+ Map.put(res, "geo", %{
+ "type" => "GeoCoordinates",
+ "latitude" => address.geom.coordinates |> elem(0),
+ "longitude" => address.geom.coordinates |> elem(1)
+ })
+ end
+ end
+
+ def make_address_data(address) do
+ Address
+ |> struct(address)
+ |> make_address_data()
+ end
+
@doc """
Make an AP comment object from an set of values
"""
diff --git a/lib/service/federator.ex b/lib/service/federator.ex
index 6be044bc..da9d5420 100644
--- a/lib/service/federator.ex
+++ b/lib/service/federator.ex
@@ -52,7 +52,7 @@ defmodule Mobilizon.Service.Federator do
Logger.debug(inspect(params))
case Transmogrifier.handle_incoming(params) do
- {:ok, activity} ->
+ {:ok, activity, _} ->
{:ok, activity}
%Activity{} ->
diff --git a/priv/repo/migrations/20190729125532_add-url-to-addresses.exs b/priv/repo/migrations/20190729125532_add-url-to-addresses.exs
new file mode 100644
index 00000000..41ed31bd
--- /dev/null
+++ b/priv/repo/migrations/20190729125532_add-url-to-addresses.exs
@@ -0,0 +1,9 @@
+defmodule :"Elixir.Mobilizon.Repo.Migrations.Add-url-to-addresses" do
+ use Ecto.Migration
+
+ def change do
+ alter table(:addresses) do
+ add(:url, :string, null: false)
+ end
+ end
+end
diff --git a/schema.graphql b/schema.graphql
index 57cf761a..e69b2c16 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -1,5 +1,5 @@
# source: http://localhost:4000/api
-# timestamp: Fri Jul 26 2019 11:28:32 GMT+0200 (GMT+02:00)
+# timestamp: Mon Jul 29 2019 15:24:10 GMT+0200 (GMT+02:00)
schema {
query: RootQueryType
@@ -121,6 +121,25 @@ type Address {
street: String
}
+input AddressInput {
+ country: String
+ description: String
+
+ """The floor this event is at"""
+ floor: String
+
+ """The geocoordinates for the point where this address is"""
+ geom: Point
+
+ """The address's locality"""
+ locality: String
+ postalCode: String
+ region: String
+
+ """The address's street name (with number)"""
+ street: String
+}
+
"""A comment"""
type Comment {
"""Internal ID for this comment"""
@@ -262,7 +281,7 @@ type Event {
"""The Event UUID"""
uuid: UUID
- """The event's visibility"""
+ """The event's visibility"""
visibility: EventVisibility
}
@@ -675,6 +694,7 @@ type RootMutationType {
onlineAddress: String
organizerActorId: ID!
phoneAddress: String
+ physicalAddress: AddressInput
"""
The picture for the event, either as an object or directly the ID of an existing Picture
@@ -891,7 +911,7 @@ type RootQueryType {
reverseGeocode(latitude: Float!, longitude: Float!): [Address]
"""Search for an address"""
- searchAddress(query: String!): [Address]
+ searchAddress(limit: Int = 10, page: Int = 1, query: String!): [Address]
"""Search events"""
searchEvents(limit: Int = 10, page: Int = 1, search: String!): Events
diff --git a/test/fixtures/mobilizon-post-activity.json b/test/fixtures/mobilizon-post-activity.json
new file mode 100644
index 00000000..b21f4bfa
--- /dev/null
+++ b/test/fixtures/mobilizon-post-activity.json
@@ -0,0 +1,66 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "mblzn": "https://joinmobilizon.org/ns#",
+ "Hashtag": "as:Hashtag",
+ "sc": "http://schema.org#",
+ "Place": "sc:Place",
+ "PostalAddress": "sc:PostalAddress",
+ "uuid": "sc:identifier"
+ }
+ ],
+ "actor": "https://event1.tcit.fr/@tcit",
+ "cc": [
+ "https://framapiaf.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ],
+ "id": "https://event1.tcit.fr/@tcit/events/109ccdfd-ee3e-46e1-a877-6c228763df0c/activity",
+ "object": {
+ "attachment": [],
+ "attributedTo": "https://event1.tcit.fr/@tcit",
+ "startTime": "2018-02-12T14:08:20Z",
+ "cc": [
+ "https://framapiaf.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ],
+ "content": "
@lain
",
+ "category": "TODO remove me",
+ "id": "https://event1.tcit.fr/@tcit/events/109ccdfd-ee3e-46e1-a877-6c228763df0c",
+ "inReplyTo": null,
+ "location": {
+ "type": "Place",
+ "name": "Locaux de Framasoft",
+ "id": "https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd",
+ "address": {
+ "type": "PostalAddress",
+ "streetAddress": "10 Rue Jangot",
+ "postalCode": "69007",
+ "addressLocality": "Lyon",
+ "addressRegion": "Auvergne Rhône Alpes",
+ "addressCountry": "France"
+ }
+ },
+ "name": "My first event",
+ "published": "2018-02-12T14:08:20Z",
+ "tag": [
+ {
+ "href": "http://localtesting.pleroma.lol/users/lain",
+ "name": "@lain@localtesting.pleroma.lol",
+ "type": "Mention"
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Event",
+ "url": "https://event1.tcit.fr/@tcit/events/109ccdfd-ee3e-46e1-a877-6c228763df0c",
+ "uuid": "109ccdfd-ee3e-46e1-a877-6c228763df0c"
+ },
+ "published": "2018-02-12T14:08:20Z",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Create"
+}
diff --git a/test/mobilizon/addresses/addresses_test.exs b/test/mobilizon/addresses/addresses_test.exs
index 04b6f78b..8f9e267f 100644
--- a/test/mobilizon/addresses/addresses_test.exs
+++ b/test/mobilizon/addresses/addresses_test.exs
@@ -1,6 +1,7 @@
defmodule Mobilizon.AddressesTest do
use Mobilizon.DataCase
+ import Mobilizon.Factory
alias Mobilizon.Addresses
describe "addresses" do
@@ -37,22 +38,13 @@ defmodule Mobilizon.AddressesTest do
# geom: nil
# }
- def address_fixture(attrs \\ %{}) do
- {:ok, address} =
- attrs
- |> Enum.into(@valid_attrs)
- |> Addresses.create_address()
-
- address
- end
-
test "list_addresses/0 returns all addresses" do
- address = address_fixture()
+ address = insert(:address)
assert [address.id] == Addresses.list_addresses() |> Enum.map(& &1.id)
end
test "get_address!/1 returns the address with given id" do
- address = address_fixture()
+ address = insert(:address)
assert Addresses.get_address!(address.id).id == address.id
end
@@ -68,7 +60,7 @@ defmodule Mobilizon.AddressesTest do
end
test "update_address/2 with valid data updates the address" do
- address = address_fixture()
+ address = insert(:address)
assert {:ok, %Address{} = address} = Addresses.update_address(address, @update_attrs)
assert address.country == "some updated addressCountry"
assert address.locality == "some updated addressLocality"
@@ -80,13 +72,13 @@ defmodule Mobilizon.AddressesTest do
end
test "delete_address/1 deletes the address" do
- address = address_fixture()
+ address = insert(:address)
assert {:ok, %Address{}} = Addresses.delete_address(address)
assert_raise Ecto.NoResultsError, fn -> Addresses.get_address!(address.id) end
end
test "change_address/1 returns a address changeset" do
- address = address_fixture()
+ address = insert(:address)
assert %Ecto.Changeset{} = Addresses.change_address(address)
end
diff --git a/test/mobilizon/service/activity_pub/activity_pub_test.exs b/test/mobilizon/service/activity_pub/activity_pub_test.exs
index c452af8d..12aa5f37 100644
--- a/test/mobilizon/service/activity_pub/activity_pub_test.exs
+++ b/test/mobilizon/service/activity_pub/activity_pub_test.exs
@@ -56,7 +56,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
test "removes doubled 'to' recipients" do
actor = insert(:actor)
- {:ok, activity} =
+ {:ok, activity, _} =
ActivityPub.create(%{
to: ["user1", "user1", "user2"],
actor: actor,
@@ -113,7 +113,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
test "it creates a delete activity and deletes the original event" do
event = insert(:event)
event = Events.get_event_full_by_url!(event.url)
- {:ok, delete} = ActivityPub.delete(event)
+ {:ok, delete, _} = ActivityPub.delete(event)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == event.organizer_actor.url
@@ -125,7 +125,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
test "it creates a delete activity and deletes the original comment" do
comment = insert(:comment)
comment = Events.get_comment_full_from_url!(comment.url)
- {:ok, delete} = ActivityPub.delete(comment)
+ {:ok, delete, _} = ActivityPub.delete(comment)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == comment.actor.url
@@ -140,7 +140,7 @@ defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
actor = insert(:actor)
actor_data = MobilizonWeb.ActivityPub.ActorView.render("actor.json", %{actor: actor})
- {:ok, update} =
+ {:ok, update, _} =
ActivityPub.update(%{
actor: actor_data["url"],
to: [actor.url <> "/followers"],
diff --git a/test/mobilizon/service/activity_pub/transmogrifier_test.exs b/test/mobilizon/service/activity_pub/transmogrifier_test.exs
index ffd8b32c..56e3e296 100644
--- a/test/mobilizon/service/activity_pub/transmogrifier_test.exs
+++ b/test/mobilizon/service/activity_pub/transmogrifier_test.exs
@@ -12,7 +12,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
alias Mobilizon.Actors
alias Mobilizon.Actors.Actor
alias Mobilizon.Events
- alias Mobilizon.Events.Comment
+ alias Mobilizon.Events.{Comment, Event}
alias Mobilizon.Service.ActivityPub.Utils
alias Mobilizon.Service.ActivityPub.Transmogrifier
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
@@ -21,7 +21,51 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
HTTPoison.start()
end
- describe "handle_incoming" do
+ describe "handle incoming events" do
+ test "it works for incoming events" do
+ data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()
+
+ {:ok, %Mobilizon.Activity{data: data, local: false}, %Event{} = event} =
+ Transmogrifier.handle_incoming(data)
+
+ assert data["id"] ==
+ "https://event1.tcit.fr/@tcit/events/109ccdfd-ee3e-46e1-a877-6c228763df0c/activity"
+
+ assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+ #
+ # assert data["cc"] == [
+ # "https://framapiaf.org/users/admin/followers",
+ # "http://localtesting.pleroma.lol/users/lain"
+ # ]
+
+ assert data["actor"] == "https://event1.tcit.fr/@tcit"
+
+ object = data["object"]
+
+ assert object["id"] ==
+ "https://event1.tcit.fr/@tcit/events/109ccdfd-ee3e-46e1-a877-6c228763df0c"
+
+ assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
+ # assert object["cc"] == [
+ # "https://framapiaf.org/users/admin/followers",
+ # "http://localtesting.pleroma.lol/users/lain"
+ # ]
+
+ assert object["actor"] == "https://event1.tcit.fr/@tcit"
+ assert object["location"]["name"] == "Locaux de Framasoft"
+ assert object["attributedTo"] == "https://event1.tcit.fr/@tcit"
+
+ assert event.physical_address.street == "10 Rue Jangot"
+
+ assert event.physical_address.url ==
+ "https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd"
+
+ {:ok, %Actor{}} = Actors.get_actor_by_url(object["actor"])
+ end
+ end
+
+ describe "handle incoming notices" do
# test "it ignores an incoming comment if we already have it" do
# comment = insert(:comment)
@@ -37,7 +81,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# |> Jason.decode!()
# |> Map.put("object", activity["object"])
- # {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+ # {:ok, returned_activity, _} = Transmogrifier.handle_incoming(data)
# assert activity == returned_activity.data
# end
@@ -55,7 +99,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# data
# |> Map.put("object", object)
- # {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+ # {:ok, returned_activity, _} = Transmogrifier.handle_incoming(data)
# assert activity =
# Activity.get_create_activity_by_object_ap_id(
@@ -71,7 +115,8 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it works for incoming notices" do
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
- {:ok, %Mobilizon.Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Mobilizon.Activity{data: data, local: false}, _} =
+ Transmogrifier.handle_incoming(data)
assert data["id"] == "https://framapiaf.org/users/admin/statuses/99512778738411822/activity"
@@ -105,7 +150,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it works for incoming notices with hashtags" do
data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
assert Enum.at(data["object"]["tag"], 2) == "moo"
end
@@ -113,7 +158,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# data =
# File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Jason.decode!()
- # {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ # {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
# assert data["object"]["content"] ==
# "@lain
"
@@ -122,7 +167,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# test "it works for incoming notices with to/cc not being an array (kroeg)" do
# data = File.read!("test/fixtures/kroeg-post-activity.json") |> Jason.decode!()
- # {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ # {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
# assert data["object"]["content"] ==
# "henlo from my Psion netBook
message sent from my Psion netBook
"
@@ -131,7 +176,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# test "it works for incoming announces with actor being inlined (kroeg)" do
# data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Jason.decode!()
- # {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ # {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
# assert data["actor"] == "https://puckipedia.com/"
# end
@@ -139,7 +184,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# test "it works for incoming notices with tag not being an array (kroeg)" do
# data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Jason.decode!()
- # {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ # {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
# assert data["object"]["emoji"] == %{
# "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
@@ -147,7 +192,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
# data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Jason.decode!()
- # {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ # {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
# assert "test" in data["object"]["tag"]
# end
@@ -170,7 +215,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
|> Jason.decode!()
|> Map.put("object", actor.url)
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "https://social.tcit.fr/users/tcit"
assert data["type"] == "Follow"
@@ -289,7 +334,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it works for incoming update activities" do
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
object =
@@ -302,7 +347,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
|> Map.put("actor", data["actor"])
|> Map.put("object", object)
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
+ {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(update_data)
{:ok, %Actor{} = actor} = Actors.get_actor_by_url(data["actor"])
assert actor.name == "gargle"
@@ -352,7 +397,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
assert Events.get_comment_from_url(comment_url)
- {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{local: false}, _} = Transmogrifier.handle_incoming(data)
refute Events.get_comment_from_url(comment_url)
end
@@ -413,14 +458,14 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
|> Jason.decode!()
|> Map.put("object", actor.url)
- {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
+ {:ok, %Activity{data: _, local: false}, _} = Transmogrifier.handle_incoming(follow_data)
data =
File.read!("test/fixtures/mastodon-unfollow-activity.json")
|> Jason.decode!()
|> Map.put("object", follow_data)
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ {:ok, %Activity{data: data, local: false}, _} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Undo"
assert data["object"]["type"] == "Follow"
@@ -706,7 +751,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
actor = insert(:actor)
other_actor = insert(:actor)
- {:ok, activity} =
+ {:ok, activity, _} =
MobilizonWeb.API.Comments.create_comment(
actor.preferred_username,
"hey, @#{other_actor.preferred_username}, how are ya? #2hu"
@@ -743,7 +788,9 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it adds the json-ld context and the conversation property" do
actor = insert(:actor)
- {:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey")
+ {:ok, activity, _} =
+ MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey")
+
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["@context"] == Utils.make_json_ld_header()["@context"]
@@ -752,7 +799,9 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
actor = insert(:actor)
- {:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey")
+ {:ok, activity, _} =
+ MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "hey")
+
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["object"]["actor"] == modified["object"]["attributedTo"]
@@ -761,7 +810,8 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it strips internal hashtag data" do
actor = insert(:actor)
- {:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "#2hu")
+ {:ok, activity, _} =
+ MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "#2hu")
expected_tag = %{
"href" => MobilizonWeb.Endpoint.url() <> "/tags/2hu",
@@ -777,7 +827,8 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
test "it strips internal fields" do
actor = insert(:actor)
- {:ok, activity} = MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "#2hu")
+ {:ok, activity, _} =
+ MobilizonWeb.API.Comments.create_comment(actor.preferred_username, "#2hu")
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs
index 3cce2fd0..f1d1e52b 100644
--- a/test/mobilizon_web/resolvers/event_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/event_resolver_test.exs
@@ -122,6 +122,95 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
]
end
+ test "create_event/3 creates an event with an address", %{
+ conn: conn,
+ actor: actor,
+ user: user
+ } do
+ address = insert(:address)
+
+ mutation = """
+ mutation {
+ createEvent(
+ 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: "birthday",
+ physical_address: {
+ street: "#{address.street}",
+ locality: "#{address.locality}"
+ }
+ ) {
+ title,
+ uuid,
+ physicalAddress {
+ url,
+ geom,
+ street
+ }
+ }
+ }
+ """
+
+ res =
+ conn
+ |> auth_conn(user)
+ |> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
+
+ assert json_response(res, 200)["errors"] == nil
+
+ assert json_response(res, 200)["data"]["createEvent"]["title"] == "my event is referenced"
+
+ assert json_response(res, 200)["data"]["createEvent"]["physicalAddress"]["street"] ==
+ address.street
+
+ refute json_response(res, 200)["data"]["createEvent"]["physicalAddress"]["url"] ==
+ address.url
+
+ mutation = """
+ mutation {
+ createEvent(
+ 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: "birthday",
+ physical_address: {
+ url: "#{address.url}"
+ }
+ ) {
+ title,
+ uuid,
+ physicalAddress {
+ url,
+ geom,
+ street
+ }
+ }
+ }
+ """
+
+ res =
+ conn
+ |> auth_conn(user)
+ |> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
+
+ assert json_response(res, 200)["errors"] == nil
+
+ assert json_response(res, 200)["data"]["createEvent"]["title"] == "my event is referenced"
+
+ assert json_response(res, 200)["data"]["createEvent"]["physicalAddress"]["street"] ==
+ address.street
+
+ assert json_response(res, 200)["data"]["createEvent"]["physicalAddress"]["url"] ==
+ address.url
+ end
+
test "create_event/3 creates an event with an attached picture", %{
conn: conn,
actor: actor,
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 0d417cdd..b8ee13cf 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -78,6 +78,7 @@ defmodule Mobilizon.Factory do
%Mobilizon.Addresses.Address{
description: sequence("MyAddress"),
geom: %Geo.Point{coordinates: {45.75, 4.85}, srid: 4326},
+ url: "http://mobilizon.test/address/#{Ecto.UUID.generate()}",
floor: "Myfloor",
country: "My Country",
locality: "My Locality",