From cdb520a95b16c7c880affd94d328c481ed5c7cf2 Mon Sep 17 00:00:00 2001
From: rustra <rustra@riseup.net>
Date: Wed, 22 Jan 2020 02:14:42 +0100
Subject: [PATCH 1/4] Split Federation as separate context

---
 config/config.exs                             |  2 +-
 config/dev.exs                                |  4 +-
 config/test.exs                               |  4 +-
 .../activity_pub/activity.ex                  |  2 +-
 .../activity_pub/activity_pub.ex              | 39 ++++++++++++-------
 .../activity_stream}/converter.ex             |  2 +-
 .../activity_stream}/converter/actor.ex       |  8 ++--
 .../activity_stream}/converter/address.ex     |  5 ++-
 .../activity_stream}/converter/comment.ex     | 12 +++---
 .../activity_stream}/converter/event.ex       | 17 ++++----
 .../activity_stream}/converter/flag.ex        | 10 ++---
 .../activity_stream}/converter/follower.ex    |  9 +++--
 .../activity_stream}/converter/participant.ex |  6 +--
 .../activity_stream}/converter/picture.ex     |  2 +-
 .../activity_stream}/converter/tombstone.ex   |  7 ++--
 .../activity_stream}/converter/utils.ex       |  8 ++--
 .../activity_stream}/convertible.ex           |  2 +-
 .../activity_pub/audience.ex                  |  8 ++--
 .../activity_pub}/federator.ex                |  7 ++--
 .../http_signatures/signature.ex              |  7 ++--
 .../activity_pub/relay.ex                     |  8 ++--
 .../activity_pub/transmogrifier.ex            | 39 +++++++++----------
 .../activity_pub/utils.ex                     | 14 ++++---
 .../activity_pub/visibility.ex                | 10 +++--
 .../activity_pub}/web_finger/web_finger.ex    | 10 ++---
 .../activity_pub/web_finger}/xml_builder.ex   | 25 ++++--------
 lib/mix/tasks/mobilizon/relay.ex              |  2 +-
 lib/mobilizon.ex                              |  5 ++-
 lib/mobilizon/actors/actors.ex                |  5 ++-
 lib/mobilizon/tombstone.ex                    |  2 +-
 lib/mobilizon_web/api/comments.ex             |  5 ++-
 lib/mobilizon_web/api/events.ex               |  6 +--
 lib/mobilizon_web/api/follows.ex              |  5 ++-
 lib/mobilizon_web/api/groups.ex               |  5 ++-
 lib/mobilizon_web/api/participations.ex       |  4 +-
 lib/mobilizon_web/api/reports.ex              |  5 ++-
 lib/mobilizon_web/api/search.ex               |  3 +-
 lib/mobilizon_web/cache/activity_pub.ex       |  8 ++--
 .../controllers/activity_pub_controller.ex    |  5 ++-
 .../controllers/web_finger_controller.ex      |  4 +-
 .../plugs/mapped_signature_to_identity.ex     | 11 ++++--
 lib/mobilizon_web/resolvers/address.ex        |  4 +-
 lib/mobilizon_web/resolvers/admin.ex          |  5 ++-
 lib/mobilizon_web/resolvers/comment.ex        |  7 ++--
 lib/mobilizon_web/resolvers/config.ex         |  3 +-
 lib/mobilizon_web/resolvers/event.ex          |  3 +-
 lib/mobilizon_web/resolvers/group.ex          |  3 +-
 lib/mobilizon_web/resolvers/person.ex         |  3 +-
 lib/mobilizon_web/resolvers/user.ex           |  2 +-
 .../views/activity_pub/actor_view.ex          |  6 ++-
 .../views/activity_pub/object_view.ex         |  2 +-
 lib/mobilizon_web/views/page_view.ex          | 15 ++++---
 .../default_scrubbler.ex}                     | 14 ++-----
 lib/service/formatter/formatter.ex            |  8 ++--
 lib/service/formatter/html.ex                 | 17 ++++++++
 lib/service/metadata.ex                       | 20 ----------
 lib/service/metadata/metadata.ex              |  7 ++++
 lib/service/metadata/utils.ex                 | 12 ++++++
 mix.exs                                       | 20 +++++-----
 .../activity_pub/activity_pub_test.exs        |  9 ++---
 .../activity_stream}/converter/actor_test.exs |  5 ++-
 .../activity_pub/relay_test.exs               |  4 +-
 .../activity_pub/transmogrifier_test.exs      | 12 +++---
 .../activity_pub/utils_test.exs               |  4 +-
 .../activity_pub}/web_finger_test.exs         |  7 ++--
 .../relay/fetch_relay_follow.json             |  4 +-
 test/mobilizon/actors/actors_test.exs         |  3 +-
 test/mobilizon_web/api/report_test.exs        |  9 +++--
 test/mobilizon_web/api/search_test.exs        |  3 +-
 .../activity_pub_controller_test.exs          |  5 ++-
 .../controllers/webfinger_controller_test.exs |  9 +++--
 .../resolvers/admin_resolver_test.exs         |  6 ++-
 .../service/admin/action_log_service_test.exs |  0
 .../service/export/icalendar_test.exs         |  0
 .../service/formatter/formatter_test.exs      |  0
 .../service/geospatial/addok_test.exs         |  0
 .../service/geospatial/geospatial_test.exs    |  0
 .../service/geospatial/google_maps_test.exs   |  0
 .../service/geospatial/map_quest_test.exs     |  0
 .../service/geospatial/nominatim_test.exs     |  0
 .../service/geospatial/photon_test.exs        |  0
 test/{mobilizon => }/service/users/tools.exs  |  0
 test/tasks/relay_test.exs                     |  3 +-
 83 files changed, 323 insertions(+), 253 deletions(-)
 rename lib/{service => federation}/activity_pub/activity.ex (83%)
 rename lib/{service => federation}/activity_pub/activity_pub.ex (97%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter.ex (76%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/actor.ex (90%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/address.ex (93%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/comment.ex (90%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/event.ex (90%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/flag.ex (90%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/follower.ex (76%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/participant.ex (72%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/picture.ex (95%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/tombstone.ex (75%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/converter/utils.ex (94%)
 rename lib/{service/activity_pub => federation/activity_pub/activity_stream}/convertible.ex (67%)
 rename lib/{service => federation}/activity_pub/audience.ex (97%)
 rename lib/{service => federation/activity_pub}/federator.ex (96%)
 rename lib/{service => federation/activity_pub}/http_signatures/signature.ex (95%)
 rename lib/{service => federation}/activity_pub/relay.ex (96%)
 rename lib/{service => federation}/activity_pub/transmogrifier.ex (95%)
 rename lib/{service => federation}/activity_pub/utils.ex (97%)
 rename lib/{service => federation}/activity_pub/visibility.ex (78%)
 rename lib/{service => federation/activity_pub}/web_finger/web_finger.ex (94%)
 rename lib/{service => federation/activity_pub/web_finger}/xml_builder.ex (69%)
 rename lib/service/{html.ex => formatter/default_scrubbler.ex} (86%)
 create mode 100644 lib/service/formatter/html.ex
 delete mode 100644 lib/service/metadata.ex
 create mode 100644 lib/service/metadata/metadata.ex
 create mode 100644 lib/service/metadata/utils.ex
 rename test/{mobilizon/service => federation}/activity_pub/activity_pub_test.exs (97%)
 rename test/{mobilizon/service/activity_pub => federation/activity_pub/activity_stream}/converter/actor_test.exs (80%)
 rename test/{mobilizon/service => federation}/activity_pub/relay_test.exs (74%)
 rename test/{mobilizon/service => federation}/activity_pub/transmogrifier_test.exs (99%)
 rename test/{mobilizon/service => federation}/activity_pub/utils_test.exs (93%)
 rename test/{mobilizon/service/web_finger => federation/activity_pub}/web_finger_test.exs (95%)
 rename test/{mobilizon => }/service/admin/action_log_service_test.exs (100%)
 rename test/{mobilizon => }/service/export/icalendar_test.exs (100%)
 rename test/{mobilizon => }/service/formatter/formatter_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/addok_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/geospatial_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/google_maps_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/map_quest_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/nominatim_test.exs (100%)
 rename test/{mobilizon => }/service/geospatial/photon_test.exs (100%)
 rename test/{mobilizon => }/service/users/tools.exs (100%)

diff --git a/config/config.exs b/config/config.exs
index b21165f62..d4996a4bb 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -120,7 +120,7 @@ config :ex_cldr,
   default_backend: Mobilizon.Cldr
 
 config :http_signatures,
-  adapter: Mobilizon.Service.HTTPSignatures.Signature
+  adapter: Mobilizon.Federation.HTTPSignatures.Signature
 
 config :mobilizon, :activitypub, sign_object_fetches: true
 
diff --git a/config/dev.exs b/config/dev.exs
index ac5f5a921..0ffb389f8 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -66,8 +66,8 @@ config :mobilizon, MobilizonWeb.Email.Mailer, adapter: Bamboo.LocalAdapter
 # Configure your database
 config :mobilizon, Mobilizon.Storage.Repo,
   types: Mobilizon.Storage.PostgresTypes,
-  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "mobilizon",
-  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "mobilizon",
+  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "postgres",
+  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "postgres",
   database: System.get_env("MOBILIZON_DATABASE_DBNAME") || "mobilizon_dev",
   hostname: System.get_env("MOBILIZON_DATABASE_HOST") || "localhost",
   port: System.get_env("MOBILIZON_DATABASE_PORT") || "5432",
diff --git a/config/test.exs b/config/test.exs
index c9ae5091e..15a3fcb77 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -24,8 +24,8 @@ config :logger,
 # Configure your database
 config :mobilizon, Mobilizon.Storage.Repo,
   types: Mobilizon.Storage.PostgresTypes,
-  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "mobilizon",
-  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "mobilizon",
+  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "postgres",
+  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "postgres",
   database: System.get_env("MOBILIZON_DATABASE_DBNAME") || "mobilizon_test",
   hostname: System.get_env("MOBILIZON_DATABASE_HOST") || "localhost",
   pool: Ecto.Adapters.SQL.Sandbox
diff --git a/lib/service/activity_pub/activity.ex b/lib/federation/activity_pub/activity.ex
similarity index 83%
rename from lib/service/activity_pub/activity.ex
rename to lib/federation/activity_pub/activity.ex
index aebf3f091..59a20ec82 100644
--- a/lib/service/activity_pub/activity.ex
+++ b/lib/federation/activity_pub/activity.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Activity do
+defmodule Mobilizon.Federation.ActivityPub.Activity do
   @moduledoc """
   Represents an activity.
   """
diff --git a/lib/service/activity_pub/activity_pub.ex b/lib/federation/activity_pub/activity_pub.ex
similarity index 97%
rename from lib/service/activity_pub/activity_pub.ex
rename to lib/federation/activity_pub/activity_pub.ex
index ee8f84793..d54eb00c7 100644
--- a/lib/service/activity_pub/activity_pub.ex
+++ b/lib/federation/activity_pub/activity_pub.ex
@@ -3,25 +3,34 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/activity_pub.ex
 
-defmodule Mobilizon.Service.ActivityPub do
+defmodule Mobilizon.Federation.ActivityPub do
   @moduledoc """
-  # ActivityPub context.
+  The ActivityPub context.
   """
 
-  import Mobilizon.Service.ActivityPub.Utils
-  import Mobilizon.Service.ActivityPub.Visibility
+  import Mobilizon.Federation.ActivityPub.Utils
 
   alias Mobilizon.{Actors, Config, Events, Reports, Users, Share}
   alias Mobilizon.Actors.{Actor, Follower}
   alias Mobilizon.Events.{Comment, Event, Participant}
   alias Mobilizon.Reports.Report
   alias Mobilizon.Tombstone
-  alias Mobilizon.Service.ActivityPub.{Activity, Converter, Convertible, Relay, Transmogrifier}
-  alias Mobilizon.Service.{Federator, WebFinger}
-  alias Mobilizon.Service.HTTPSignatures.Signature
+
+  alias Mobilizon.Federation.ActivityPub.{
+    Activity,
+    Audience,
+    Federator,
+    Relay,
+    Transmogrifier,
+    Visibility,
+    WebFinger
+  }
+
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
+  alias Mobilizon.Federation.HTTPSignatures.Signature
+
   alias MobilizonWeb.API.Utils, as: APIUtils
-  alias Mobilizon.Service.ActivityPub.Audience
-  alias Mobilizon.Service.ActivityPub.Converter.Utils, as: ConverterUtils
   alias MobilizonWeb.Email.{Admin, Mailer}
 
   require Logger
@@ -50,7 +59,7 @@ defmodule Mobilizon.Service.ActivityPub do
   def fetch_object_from_url(url) do
     Logger.info("Fetching object from url #{url}")
 
-    date = Mobilizon.Service.HTTPSignatures.Signature.generate_date_header()
+    date = Signature.generate_date_header()
 
     headers =
       [{:Accept, "application/activity+json"}]
@@ -149,7 +158,7 @@ defmodule Mobilizon.Service.ActivityPub do
 
   * Creates the object, which returns AS data
   * Wraps ActivityStreams data into a `Create` activity
-  * Creates an `Mobilizon.Service.ActivityPub.Activity` from this
+  * Creates an `Mobilizon.Federation.ActivityPub.Activity` from this
   * Federates (asynchronously) the activity
   * Returns the activity
   """
@@ -181,7 +190,7 @@ defmodule Mobilizon.Service.ActivityPub do
 
   * Updates the object, which returns AS data
   * Wraps ActivityStreams data into a `Update` activity
-  * Creates an `Mobilizon.Service.ActivityPub.Activity` from this
+  * Creates an `Mobilizon.Federation.ActivityPub.Activity` from this
   * Federates (asynchronously) the activity
   * Returns the activity
   """
@@ -251,7 +260,7 @@ defmodule Mobilizon.Service.ActivityPub do
         local \\ true,
         public \\ true
       ) do
-    with true <- is_public?(object),
+    with true <- Visibility.is_public?(object),
          {:ok, %Actor{id: object_owner_actor_id}} <- Actors.get_actor_by_url(object["actor"]),
          {:ok, %Share{} = _share} <- Share.create(object["id"], actor.id, object_owner_actor_id),
          announce_data <- make_announce_data(actor, object, activity_id, public),
@@ -549,7 +558,7 @@ defmodule Mobilizon.Service.ActivityPub do
     Logger.debug("Publishing an activity")
     Logger.debug(inspect(activity))
 
-    public = is_public?(activity)
+    public = Visibility.is_public?(activity)
     Logger.debug("is public ? #{public}")
 
     if public && is_create_activity?(activity) && Config.get([:instance, :allow_relay]) do
@@ -629,7 +638,7 @@ defmodule Mobilizon.Service.ActivityPub do
            :ok <- Logger.debug("response okay, now decoding json"),
            {:ok, data} <- Jason.decode(body) do
         Logger.debug("Got activity+json response at actor's endpoint, now converting data")
-        Mobilizon.Service.ActivityPub.Converter.Actor.as_to_model_data(data)
+        Converter.Actor.as_to_model_data(data)
       else
         # Actor is gone, probably deleted
         {:ok, %HTTPoison.Response{status_code: 410}} ->
diff --git a/lib/service/activity_pub/converter.ex b/lib/federation/activity_pub/activity_stream/converter.ex
similarity index 76%
rename from lib/service/activity_pub/converter.ex
rename to lib/federation/activity_pub/activity_stream/converter.ex
index 920efada7..39c21b4c9 100644
--- a/lib/service/activity_pub/converter.ex
+++ b/lib/federation/activity_pub/activity_stream/converter.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter do
   @moduledoc """
   Converter behaviour.
 
diff --git a/lib/service/activity_pub/converter/actor.ex b/lib/federation/activity_pub/activity_stream/converter/actor.ex
similarity index 90%
rename from lib/service/activity_pub/converter/actor.ex
rename to lib/federation/activity_pub/activity_stream/converter/actor.ex
index 556a4d8b9..f28da9e17 100644
--- a/lib/service/activity_pub/converter/actor.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/actor.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Actor do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor do
   @moduledoc """
   Actor converter.
 
@@ -7,12 +7,14 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Actor do
   """
 
   alias Mobilizon.Actors.Actor, as: ActorModel
-  alias Mobilizon.Service.ActivityPub.{Converter, Convertible, Utils}
+
+  alias Mobilizon.Federation.ActivityPub.Utils
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
 
   @behaviour Converter
 
   defimpl Convertible, for: ActorModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Actor, as: ActorConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor, as: ActorConverter
 
     defdelegate model_to_as(actor), to: ActorConverter
   end
diff --git a/lib/service/activity_pub/converter/address.ex b/lib/federation/activity_pub/activity_stream/converter/address.ex
similarity index 93%
rename from lib/service/activity_pub/converter/address.ex
rename to lib/federation/activity_pub/activity_stream/converter/address.ex
index 413c23c30..b24296fae 100644
--- a/lib/service/activity_pub/converter/address.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/address.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Address do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Address do
   @moduledoc """
   Address converter.
 
@@ -7,7 +7,8 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Address do
   """
 
   alias Mobilizon.Addresses.Address, as: AddressModel
-  alias Mobilizon.Service.ActivityPub.Converter
+
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
 
   @behaviour Converter
 
diff --git a/lib/service/activity_pub/converter/comment.ex b/lib/federation/activity_pub/activity_stream/converter/comment.ex
similarity index 90%
rename from lib/service/activity_pub/converter/comment.ex
rename to lib/federation/activity_pub/activity_stream/converter/comment.ex
index c82cb03a4..b9e7d43fc 100644
--- a/lib/service/activity_pub/converter/comment.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/comment.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Comment do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Comment do
   @moduledoc """
   Comment converter.
 
@@ -9,17 +9,19 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Comment do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.Comment, as: CommentModel
   alias Mobilizon.Events.Event
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Converter, Convertible, Visibility}
-  alias Mobilizon.Service.ActivityPub.Converter.Utils, as: ConverterUtils
   alias Mobilizon.Tombstone, as: TombstoneModel
 
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Visibility
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
+
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: CommentModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Comment, as: CommentConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Comment, as: CommentConverter
 
     defdelegate model_to_as(comment), to: CommentConverter
   end
diff --git a/lib/service/activity_pub/converter/event.ex b/lib/federation/activity_pub/activity_stream/converter/event.ex
similarity index 90%
rename from lib/service/activity_pub/converter/event.ex
rename to lib/federation/activity_pub/activity_stream/converter/event.ex
index d02065fe8..76c31ad61 100644
--- a/lib/service/activity_pub/converter/event.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/event.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Event do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Event do
   @moduledoc """
   Event converter.
 
@@ -11,18 +11,19 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do
   alias Mobilizon.Addresses.Address
   alias Mobilizon.Events.Event, as: EventModel
   alias Mobilizon.Media.Picture
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Converter, Convertible}
-  alias Mobilizon.Service.ActivityPub.Converter.Address, as: AddressConverter
-  alias Mobilizon.Service.ActivityPub.Converter.Picture, as: PictureConverter
-  alias Mobilizon.Service.ActivityPub.Converter.Utils, as: ConverterUtils
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Address, as: AddressConverter
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Picture, as: PictureConverter
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
 
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: EventModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Event, as: EventConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Event, as: EventConverter
 
     defdelegate model_to_as(event), to: EventConverter
   end
@@ -177,7 +178,7 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Event do
 
   @spec do_get_address(map) :: integer | nil
   defp do_get_address(map) do
-    map = Mobilizon.Service.ActivityPub.Converter.Address.as_to_model_data(map)
+    map = AddressConverter.as_to_model_data(map)
 
     case Addresses.create_address(map) do
       {:ok, %Address{id: address_id}} ->
diff --git a/lib/service/activity_pub/converter/flag.ex b/lib/federation/activity_pub/activity_stream/converter/flag.ex
similarity index 90%
rename from lib/service/activity_pub/converter/flag.ex
rename to lib/federation/activity_pub/activity_stream/converter/flag.ex
index 2980b0c69..bd50a8031 100644
--- a/lib/service/activity_pub/converter/flag.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/flag.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Flag do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Flag do
   @moduledoc """
   Flag converter.
 
@@ -13,14 +13,14 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Flag do
   alias Mobilizon.Events
   alias Mobilizon.Events.Event
   alias Mobilizon.Reports.Report
-  alias Mobilizon.Service.ActivityPub.Converter
-  alias Mobilizon.Service.ActivityPub.Convertible
-  alias Mobilizon.Service.ActivityPub.Relay
+
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityPub.Relay
 
   @behaviour Converter
 
   defimpl Convertible, for: Report do
-    alias Mobilizon.Service.ActivityPub.Converter.Flag, as: FlagConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Flag, as: FlagConverter
 
     defdelegate model_to_as(report), to: FlagConverter
   end
diff --git a/lib/service/activity_pub/converter/follower.ex b/lib/federation/activity_pub/activity_stream/converter/follower.ex
similarity index 76%
rename from lib/service/activity_pub/converter/follower.ex
rename to lib/federation/activity_pub/activity_stream/converter/follower.ex
index 4854366c3..d280a3f69 100644
--- a/lib/service/activity_pub/converter/follower.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/follower.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Follower do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Follower do
   @moduledoc """
   Participant converter.
 
@@ -6,13 +6,14 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Follower do
   internal one, and back.
   """
 
+  alias Mobilizon.Actors.Actor
   alias Mobilizon.Actors.Follower, as: FollowerModel
 
-  alias Mobilizon.Service.ActivityPub.Convertible
-  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
 
   defimpl Convertible, for: FollowerModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Follower, as: FollowerConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Follower,
+      as: FollowerConverter
 
     defdelegate model_to_as(follower), to: FollowerConverter
   end
diff --git a/lib/service/activity_pub/converter/participant.ex b/lib/federation/activity_pub/activity_stream/converter/participant.ex
similarity index 72%
rename from lib/service/activity_pub/converter/participant.ex
rename to lib/federation/activity_pub/activity_stream/converter/participant.ex
index d50e892e8..51eb26ea6 100644
--- a/lib/service/activity_pub/converter/participant.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/participant.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Participant do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Participant do
   @moduledoc """
   Participant converter.
 
@@ -8,10 +8,10 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Participant do
 
   alias Mobilizon.Events.Participant, as: ParticipantModel
 
-  alias Mobilizon.Service.ActivityPub.Convertible
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
 
   defimpl Convertible, for: ParticipantModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Participant, as: ParticipantConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Participant, as: ParticipantConverter
 
     defdelegate model_to_as(participant), to: ParticipantConverter
   end
diff --git a/lib/service/activity_pub/converter/picture.ex b/lib/federation/activity_pub/activity_stream/converter/picture.ex
similarity index 95%
rename from lib/service/activity_pub/converter/picture.ex
rename to lib/federation/activity_pub/activity_stream/converter/picture.ex
index 292db9bda..2c4b0894c 100644
--- a/lib/service/activity_pub/converter/picture.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/picture.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Picture do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Picture do
   @moduledoc """
   Picture converter.
 
diff --git a/lib/service/activity_pub/converter/tombstone.ex b/lib/federation/activity_pub/activity_stream/converter/tombstone.ex
similarity index 75%
rename from lib/service/activity_pub/converter/tombstone.ex
rename to lib/federation/activity_pub/activity_stream/converter/tombstone.ex
index 8054ae376..d782c0bf9 100644
--- a/lib/service/activity_pub/converter/tombstone.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/tombstone.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Tombstone do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Tombstone do
   @moduledoc """
   Comment converter.
 
@@ -6,14 +6,15 @@ defmodule Mobilizon.Service.ActivityPub.Converter.Tombstone do
   """
 
   alias Mobilizon.Tombstone, as: TombstoneModel
-  alias Mobilizon.Service.ActivityPub.{Converter, Convertible}
+
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
 
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: TombstoneModel do
-    alias Mobilizon.Service.ActivityPub.Converter.Tombstone, as: TombstoneConverter
+    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Tombstone, as: TombstoneConverter
 
     defdelegate model_to_as(comment), to: TombstoneConverter
   end
diff --git a/lib/service/activity_pub/converter/utils.ex b/lib/federation/activity_pub/activity_stream/converter/utils.ex
similarity index 94%
rename from lib/service/activity_pub/converter/utils.ex
rename to lib/federation/activity_pub/activity_stream/converter/utils.ex
index 8e637736f..06c656603 100644
--- a/lib/service/activity_pub/converter/utils.ex
+++ b/lib/federation/activity_pub/activity_stream/converter/utils.ex
@@ -1,14 +1,16 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.Utils do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils do
   @moduledoc """
-  Various utils for converters
+  Various utils for converters.
   """
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.Tag
   alias Mobilizon.Mention
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Storage.Repo
+
+  alias Mobilizon.Federation.ActivityPub
+
   require Logger
 
   @spec fetch_tags([String.t()]) :: [Tag.t()]
diff --git a/lib/service/activity_pub/convertible.ex b/lib/federation/activity_pub/activity_stream/convertible.ex
similarity index 67%
rename from lib/service/activity_pub/convertible.ex
rename to lib/federation/activity_pub/activity_stream/convertible.ex
index a757cc413..cb27a76cc 100644
--- a/lib/service/activity_pub/convertible.ex
+++ b/lib/federation/activity_pub/activity_stream/convertible.ex
@@ -1,4 +1,4 @@
-defprotocol Mobilizon.Service.ActivityPub.Convertible do
+defprotocol Mobilizon.Federation.ActivityPub.ActivityStream.Convertible do
   @moduledoc """
   Convertible protocol.
   """
diff --git a/lib/service/activity_pub/audience.ex b/lib/federation/activity_pub/audience.ex
similarity index 97%
rename from lib/service/activity_pub/audience.ex
rename to lib/federation/activity_pub/audience.ex
index cca7d1f66..7f7566865 100644
--- a/lib/service/activity_pub/audience.ex
+++ b/lib/federation/activity_pub/audience.ex
@@ -1,13 +1,13 @@
-defmodule Mobilizon.Service.ActivityPub.Audience do
+defmodule Mobilizon.Federation.ActivityPub.Audience do
   @moduledoc """
   Tools for calculating content audience
   """
+
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Events.Comment
-  alias Mobilizon.Events.Event
-  alias Mobilizon.Events.Participant
+  alias Mobilizon.Events.{Comment, Event, Participant}
   alias Mobilizon.Share
+
   require Logger
 
   @ap_public "https://www.w3.org/ns/activitystreams#Public"
diff --git a/lib/service/federator.ex b/lib/federation/activity_pub/federator.ex
similarity index 96%
rename from lib/service/federator.ex
rename to lib/federation/activity_pub/federator.ex
index 2466468ff..f52d1531f 100644
--- a/lib/service/federator.ex
+++ b/lib/federation/activity_pub/federator.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/federator/federator.ex
 
-defmodule Mobilizon.Service.Federator do
+defmodule Mobilizon.Federation.ActivityPub.Federator do
   @moduledoc """
   Handle federated activities
   """
@@ -11,8 +11,9 @@ defmodule Mobilizon.Service.Federator do
   use GenServer
 
   alias Mobilizon.Actors
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Activity, Transmogrifier}
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier}
 
   require Logger
 
diff --git a/lib/service/http_signatures/signature.ex b/lib/federation/activity_pub/http_signatures/signature.ex
similarity index 95%
rename from lib/service/http_signatures/signature.ex
rename to lib/federation/activity_pub/http_signatures/signature.ex
index df929617f..3cdc10dcf 100644
--- a/lib/service/http_signatures/signature.ex
+++ b/lib/federation/activity_pub/http_signatures/signature.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/signature.ex
 
-defmodule Mobilizon.Service.HTTPSignatures.Signature do
+defmodule Mobilizon.Federation.HTTPSignatures.Signature do
   @moduledoc """
   Adapter for the `HTTPSignatures` lib that handles signing and providing public keys to verify HTTPSignatures
   """
@@ -11,7 +11,8 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
   @behaviour HTTPSignatures.Adapter
 
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub
+
+  alias Mobilizon.Federation.ActivityPub
 
   require Logger
 
@@ -111,6 +112,6 @@ defmodule Mobilizon.Service.HTTPSignatures.Signature do
   def generate_request_target(method, path), do: "#{method} #{path}"
 
   def build_digest(body) do
-    "SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64())
+    "SHA-256=#{:sha256 |> :crypto.hash(body) |> Base.encode64()}"
   end
 end
diff --git a/lib/service/activity_pub/relay.ex b/lib/federation/activity_pub/relay.ex
similarity index 96%
rename from lib/service/activity_pub/relay.ex
rename to lib/federation/activity_pub/relay.ex
index eb45e0d10..111699de1 100644
--- a/lib/service/activity_pub/relay.ex
+++ b/lib/federation/activity_pub/relay.ex
@@ -3,16 +3,16 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/relay.ex
 
-defmodule Mobilizon.Service.ActivityPub.Relay do
+defmodule Mobilizon.Federation.ActivityPub.Relay do
   @moduledoc """
   Handles following and unfollowing relays and instances.
   """
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.{Actor, Follower}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Activity, Transmogrifier}
-  alias Mobilizon.Service.WebFinger
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier, WebFinger}
 
   alias MobilizonWeb.API.Follows
 
diff --git a/lib/service/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex
similarity index 95%
rename from lib/service/activity_pub/transmogrifier.ex
rename to lib/federation/activity_pub/transmogrifier.ex
index d21d965da..486df279c 100644
--- a/lib/service/activity_pub/transmogrifier.ex
+++ b/lib/federation/activity_pub/transmogrifier.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/transmogrifier.ex
 
-defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
+defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
   @moduledoc """
   A module to handle coding from internal to wire ActivityPub and back.
   """
@@ -12,11 +12,12 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   alias Mobilizon.Actors.{Actor, Follower}
   alias Mobilizon.Events
   alias Mobilizon.Events.{Comment, Event, Participant}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Activity, Converter, Convertible, Utils}
-  alias MobilizonWeb.Email.Participation
 
-  import Mobilizon.Service.ActivityPub.Utils
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+
+  alias MobilizonWeb.Email.Participation
 
   require Logger
 
@@ -117,7 +118,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
           "id" => id
         } = data
       ) do
-    with actor_url <- get_actor(data),
+    with actor_url <- Utils.get_actor(data),
          {:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_actor_by_url(actor_url),
          {:object_not_found, {:ok, %Activity{} = activity, object}} <-
            {:object_not_found,
@@ -146,7 +147,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Reject", "object" => rejected_object, "actor" => _actor, "id" => id} = data
       ) do
-    with actor_url <- get_actor(data),
+    with actor_url <- Utils.get_actor(data),
          {:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_actor_by_url(actor_url),
          {:object_not_found, {:ok, activity, object}} <-
            {:object_not_found,
@@ -175,14 +176,13 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Announce", "object" => object, "actor" => _actor, "id" => _id} = data
       ) do
-    with actor <- get_actor(data),
+    with actor <- Utils.get_actor(data),
          # TODO: Is the following line useful?
          {:ok, %Actor{id: actor_id} = _actor} <- ActivityPub.get_or_fetch_actor_by_url(actor),
          :ok <- Logger.debug("Fetching contained object"),
          {:ok, object} <- fetch_obj_helper_as_activity_streams(object),
          :ok <- Logger.debug("Handling contained object"),
-         create_data <-
-           make_create_data(object),
+         create_data <- Utils.make_create_data(object),
          :ok <- Logger.debug(inspect(object)),
          {:ok, _activity, entity} <- handle_incoming(create_data),
          :ok <- Logger.debug("Finished processing contained object"),
@@ -221,13 +221,12 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
         %{"type" => "Update", "object" => %{"type" => "Event"} = object, "actor" => _actor} =
           update_data
       ) do
-    with actor <- get_actor(update_data),
+        with actor <- Utils.get_actor(update_data),
          {:ok, %Actor{url: actor_url}} <- Actors.get_actor_by_url(actor),
          {:ok, %Event{} = old_event} <-
            object |> Utils.get_url() |> ActivityPub.fetch_object_from_url(),
-         {:ok, object_data} <-
-           object |> Converter.Event.as_to_model_data(),
-         {:origin_check, true} <- {:origin_check, origin_check?(actor_url, update_data)},
+         {:ok, object_data} <- Converter.Event.as_to_model_data(object),
+         {:origin_check, true} <- {:origin_check, Utils.origin_check?(actor_url, update_data)},
          {:ok, %Activity{} = activity, %Event{} = new_event} <-
            ActivityPub.update(:event, old_event, object_data, false) do
       {:ok, activity, new_event}
@@ -249,7 +248,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
           "id" => id
         } = data
       ) do
-    with actor <- get_actor(data),
+    with actor <- Utils.get_actor(data),
          {:ok, %Actor{} = actor} <- ActivityPub.get_or_fetch_actor_by_url(actor),
          {:ok, object} <- fetch_obj_helper_as_activity_streams(object_id),
          {:ok, activity, object} <-
@@ -287,10 +286,10 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Delete", "object" => object, "actor" => _actor, "id" => _id} = data
       ) do
-    with actor <- get_actor(data),
+    with actor <- Utils.get_actor(data),
          {:ok, %Actor{url: actor_url}} <- Actors.get_actor_by_url(actor),
          object_id <- Utils.get_url(object),
-         {:origin_check, true} <- {:origin_check, origin_check_from_id?(actor_url, object_id)},
+         {:origin_check, true} <- {:origin_check, Utils.origin_check_from_id?(actor_url, object_id)},
          {:ok, object} <- ActivityPub.fetch_object_from_url(object_id),
          {:ok, activity, object} <- ActivityPub.delete(object, false) do
       {:ok, activity, object}
@@ -308,7 +307,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Join", "object" => object, "actor" => _actor, "id" => id} = data
       ) do
-    with actor <- get_actor(data),
+    with actor <- Utils.get_actor(data),
          {:ok, %Actor{url: _actor_url} = actor} <- Actors.get_actor_by_url(actor),
          object <- Utils.get_url(object),
          {:ok, object} <- ActivityPub.fetch_object_from_url(object),
@@ -324,7 +323,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   def handle_incoming(
         %{"type" => "Leave", "object" => object, "actor" => actor, "id" => _id} = data
       ) do
-    with actor <- get_actor(data),
+    with actor <- Utils.get_actor(data),
          {:ok, %Actor{} = actor} <- Actors.get_actor_by_url(actor),
          object <- Utils.get_url(object),
          {:ok, object} <- ActivityPub.fetch_object_from_url(object),
@@ -356,7 +355,7 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
   #         "id" => id
   #       } = data
   #     ) do
-  #   with actor <- get_actor(data),
+  #   with actor <- Utils.get_actor(data),
   #        %Actor{} = actor <- ActivityPub.get_or_fetch_actor_by_url(actor),
   #        {:ok, object} <- fetch_obj_helper(object_id) || fetch_obj_helper(object_id),
   #        {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
diff --git a/lib/service/activity_pub/utils.ex b/lib/federation/activity_pub/utils.ex
similarity index 97%
rename from lib/service/activity_pub/utils.ex
rename to lib/federation/activity_pub/utils.ex
index 586fb890a..53485908e 100644
--- a/lib/service/activity_pub/utils.ex
+++ b/lib/federation/activity_pub/utils.ex
@@ -3,16 +3,18 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/utils.ex
 
-defmodule Mobilizon.Service.ActivityPub.Utils do
+defmodule Mobilizon.Federation.ActivityPub.Utils do
   @moduledoc """
-  # Various ActivityPub related utils.
+  Various ActivityPub related utils.
   """
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Media.Picture
-  alias Mobilizon.Service.ActivityPub.{Activity, Converter}
-  alias Mobilizon.Service.Federator
+
+  alias Mobilizon.Federation.ActivityPub.{Activity, Federator, Relay}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
+  alias Mobilizon.Federation.HTTPSignatures
 
   require Logger
 
@@ -422,8 +424,8 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
     uri = URI.parse(id)
 
     signature =
-      Mobilizon.Service.ActivityPub.Relay.get_actor()
-      |> Mobilizon.Service.HTTPSignatures.Signature.sign(%{
+      Relay.get_actor()
+      |> HTTPSignatures.Signature.sign(%{
         "(request-target)": "get #{uri.path}",
         host: uri.host,
         date: date
diff --git a/lib/service/activity_pub/visibility.ex b/lib/federation/activity_pub/visibility.ex
similarity index 78%
rename from lib/service/activity_pub/visibility.ex
rename to lib/federation/activity_pub/visibility.ex
index fa89c6ec9..0bfb7e9ca 100644
--- a/lib/service/activity_pub/visibility.ex
+++ b/lib/federation/activity_pub/visibility.ex
@@ -3,13 +3,14 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/visibility.ex
 
-defmodule Mobilizon.Service.ActivityPub.Visibility do
+defmodule Mobilizon.Federation.ActivityPub.Visibility do
   @moduledoc """
   Utility functions related to content visibility
   """
 
   alias Mobilizon.Events.Comment
-  alias Mobilizon.Service.ActivityPub.Activity
+
+  alias Mobilizon.Federation.ActivityPub.Activity
 
   @public "https://www.w3.org/ns/activitystreams#Public"
 
@@ -18,8 +19,9 @@ defmodule Mobilizon.Service.ActivityPub.Visibility do
   def is_public?(%{data: data}), do: is_public?(data)
   def is_public?(%Activity{data: data}), do: is_public?(data)
 
-  def is_public?(data) when is_map(data),
-    do: @public in (Map.get(data, "to", []) ++ Map.get(data, "cc", []))
+  def is_public?(data) when is_map(data) do
+    @public in (Map.get(data, "to", []) ++ Map.get(data, "cc", []))
+  end
 
   def is_public?(%Comment{deleted_at: deleted_at}), do: !is_nil(deleted_at)
   def is_public?(err), do: raise(ArgumentError, message: "Invalid argument #{inspect(err)}")
diff --git a/lib/service/web_finger/web_finger.ex b/lib/federation/activity_pub/web_finger/web_finger.ex
similarity index 94%
rename from lib/service/web_finger/web_finger.ex
rename to lib/federation/activity_pub/web_finger/web_finger.ex
index d1ac160fb..3e9459a54 100644
--- a/lib/service/web_finger/web_finger.ex
+++ b/lib/federation/activity_pub/web_finger/web_finger.ex
@@ -3,16 +3,16 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/web_finger/web_finger.ex
 
-defmodule Mobilizon.Service.WebFinger do
+defmodule Mobilizon.Federation.ActivityPub.WebFinger do
   @moduledoc """
-  # WebFinger
-
-  Performs the WebFinger requests and responses (JSON only)
+  Performs the WebFinger requests and responses (JSON only).
   """
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.XmlBuilder
+
+  alias Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder
+
   require Jason
   require Logger
 
diff --git a/lib/service/xml_builder.ex b/lib/federation/activity_pub/web_finger/xml_builder.ex
similarity index 69%
rename from lib/service/xml_builder.ex
rename to lib/federation/activity_pub/web_finger/xml_builder.ex
index ac32a45b5..0c7cf45e6 100644
--- a/lib/service/xml_builder.ex
+++ b/lib/federation/activity_pub/web_finger/xml_builder.ex
@@ -3,16 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/xml_builder.ex
 
-defmodule Mobilizon.Service.XmlBuilder do
+defmodule Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder do
   @moduledoc """
-  XML Builder.
-
-  Needed to build XRD for webfinger host_meta
+  Builds XRD for WebFinger host_meta.
   """
 
   def to_xml({tag, attributes, content}) do
     open_tag = make_open_tag(tag, attributes)
-
     content_xml = to_xml(content)
 
     "<#{open_tag}>#{content_xml}</#{tag}>"
@@ -26,28 +23,22 @@ defmodule Mobilizon.Service.XmlBuilder do
 
   def to_xml({tag, content}), do: to_xml({tag, %{}, content})
 
-  def to_xml(content) when is_binary(content) do
-    to_string(content)
-  end
+  def to_xml(content) when is_binary(content), do: to_string(content)
 
   def to_xml(content) when is_list(content) do
-    for element <- content do
-      to_xml(element)
-    end
+    content
+    |> Enum.map(&to_xml/1)
     |> Enum.join()
   end
 
-  def to_xml(%NaiveDateTime{} = time) do
-    NaiveDateTime.to_iso8601(time)
-  end
+  def to_xml(%NaiveDateTime{} = time), do: NaiveDateTime.to_iso8601(time)
 
   def to_doc(content), do: ~s(<?xml version="1.0" encoding="UTF-8"?>) <> to_xml(content)
 
   defp make_open_tag(tag, attributes) do
     attributes_string =
-      for {attribute, value} <- attributes do
-        "#{attribute}=\"#{value}\""
-      end
+      attributes
+      |> Enum.map(fn {attribute, value} -> "#{attribute}=\"#{value}\"" end)
       |> Enum.join(" ")
 
     [tag, attributes_string] |> Enum.join(" ") |> String.trim()
diff --git a/lib/mix/tasks/mobilizon/relay.ex b/lib/mix/tasks/mobilizon/relay.ex
index 0e88ea603..f7f0830a4 100644
--- a/lib/mix/tasks/mobilizon/relay.ex
+++ b/lib/mix/tasks/mobilizon/relay.ex
@@ -23,7 +23,7 @@ defmodule Mix.Tasks.Mobilizon.Relay do
   use Mix.Task
 
   alias Mix.Tasks.Mobilizon.Common
-  alias Mobilizon.Service.ActivityPub.Relay
+  alias Mobilizon.Federation.ActivityPub.Relay
 
   @shortdoc "Manages remote relays"
   def run(["follow", target]) do
diff --git a/lib/mobilizon.ex b/lib/mobilizon.ex
index 49443f84d..6f31f7f62 100644
--- a/lib/mobilizon.ex
+++ b/lib/mobilizon.ex
@@ -15,6 +15,7 @@ defmodule Mobilizon do
   import Cachex.Spec
 
   alias Mobilizon.Config
+  alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Service.Export.{Feed, ICalendar}
 
   @name Mix.Project.config()[:name]
@@ -41,7 +42,7 @@ defmodule Mobilizon do
       {Oban, Application.get_env(:mobilizon, Oban)},
       # workers
       Guardian.DB.Token.SweeperServer,
-      Mobilizon.Service.Federator,
+      ActivityPub.Federator,
       cachex_spec(:feed, 2500, 60, 60, &Feed.create_cache/1),
       cachex_spec(:ics, 2500, 60, 60, &ICalendar.create_cache/1),
       cachex_spec(:statistics, 10, 60, 60),
@@ -94,7 +95,7 @@ defmodule Mobilizon do
   defp internal_actor() do
     %{
       id: :internal_actor_init,
-      start: {Task, :start_link, [&Mobilizon.Service.ActivityPub.Relay.init/0]},
+      start: {Task, :start_link, [&ActivityPub.Relay.init/0]},
       restart: :temporary
     }
   end
diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex
index 0a70d6cbe..44d977ecf 100644
--- a/lib/mobilizon/actors/actors.ex
+++ b/lib/mobilizon/actors/actors.ex
@@ -11,9 +11,10 @@ defmodule Mobilizon.Actors do
   alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
   alias Mobilizon.{Crypto, Events}
   alias Mobilizon.Media.File
-  alias Mobilizon.Storage.{Page, Repo}
   alias Mobilizon.Service.Workers.BackgroundWorker
-  alias Mobilizon.Service.ActivityPub
+  alias Mobilizon.Storage.{Page, Repo}
+
+  alias Mobilizon.Federation.ActivityPub
 
   require Logger
 
diff --git a/lib/mobilizon/tombstone.ex b/lib/mobilizon/tombstone.ex
index e409fa84b..864228cca 100644
--- a/lib/mobilizon/tombstone.ex
+++ b/lib/mobilizon/tombstone.ex
@@ -31,7 +31,7 @@ defmodule Mobilizon.Tombstone do
     |> validate_required(@required_attrs)
   end
 
-  @spec create_tombstone(map()) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
+  @spec create_tombstone(map) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
   def create_tombstone(attrs) do
     %__MODULE__{}
     |> changeset(attrs)
diff --git a/lib/mobilizon_web/api/comments.ex b/lib/mobilizon_web/api/comments.ex
index e3feb3056..24fe79771 100644
--- a/lib/mobilizon_web/api/comments.ex
+++ b/lib/mobilizon_web/api/comments.ex
@@ -3,8 +3,9 @@ defmodule MobilizonWeb.API.Comments do
   API for Comments.
   """
   alias Mobilizon.Events.Comment
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.Activity
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Activity
 
   @doc """
   Create a comment
diff --git a/lib/mobilizon_web/api/events.ex b/lib/mobilizon_web/api/events.ex
index d26752772..2db2b7984 100644
--- a/lib/mobilizon_web/api/events.ex
+++ b/lib/mobilizon_web/api/events.ex
@@ -5,9 +5,9 @@ defmodule MobilizonWeb.API.Events do
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.Event
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.Activity
-  alias Mobilizon.Service.ActivityPub.Utils
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
 
   @doc """
   Create an event
diff --git a/lib/mobilizon_web/api/follows.ex b/lib/mobilizon_web/api/follows.ex
index c86f6d3f4..ca4e11af2 100644
--- a/lib/mobilizon_web/api/follows.ex
+++ b/lib/mobilizon_web/api/follows.ex
@@ -5,8 +5,9 @@ defmodule MobilizonWeb.API.Follows do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.{Actor, Follower}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.Activity
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Activity
 
   require Logger
 
diff --git a/lib/mobilizon_web/api/groups.ex b/lib/mobilizon_web/api/groups.ex
index d19329e71..b8747a8cc 100644
--- a/lib/mobilizon_web/api/groups.ex
+++ b/lib/mobilizon_web/api/groups.ex
@@ -5,8 +5,9 @@ defmodule MobilizonWeb.API.Groups do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.Activity
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Activity
 
   @doc """
   Create a group
diff --git a/lib/mobilizon_web/api/participations.ex b/lib/mobilizon_web/api/participations.ex
index 3bd6a348e..4c53d5005 100644
--- a/lib/mobilizon_web/api/participations.ex
+++ b/lib/mobilizon_web/api/participations.ex
@@ -5,7 +5,9 @@ defmodule MobilizonWeb.API.Participations do
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.{Event, Participant}
-  alias Mobilizon.Service.ActivityPub
+
+  alias Mobilizon.Federation.ActivityPub
+
   alias MobilizonWeb.Email.Participation
 
   @spec join(Event.t(), Actor.t()) :: {:ok, Participant.t()}
diff --git a/lib/mobilizon_web/api/reports.ex b/lib/mobilizon_web/api/reports.ex
index 278ef828d..8fd7f68c2 100644
--- a/lib/mobilizon_web/api/reports.ex
+++ b/lib/mobilizon_web/api/reports.ex
@@ -8,11 +8,12 @@ defmodule MobilizonWeb.API.Reports do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Reports, as: ReportsAction
   alias Mobilizon.Reports.{Note, Report, ReportStatus}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.Activity
   alias Mobilizon.Users
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Activity
+
   @doc """
   Create a report/flag on an actor, and optionally on an event or on comments.
   """
diff --git a/lib/mobilizon_web/api/search.ex b/lib/mobilizon_web/api/search.ex
index 0124afb5f..7cb2d600d 100644
--- a/lib/mobilizon_web/api/search.ex
+++ b/lib/mobilizon_web/api/search.ex
@@ -6,9 +6,10 @@ defmodule MobilizonWeb.API.Search do
   alias Mobilizon.Actors
   alias Mobilizon.Actors.ActorType
   alias Mobilizon.Events
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Storage.Page
 
+  alias Mobilizon.Federation.ActivityPub
+
   require Logger
 
   @doc """
diff --git a/lib/mobilizon_web/cache/activity_pub.ex b/lib/mobilizon_web/cache/activity_pub.ex
index 14c768256..d91c1cb17 100644
--- a/lib/mobilizon_web/cache/activity_pub.ex
+++ b/lib/mobilizon_web/cache/activity_pub.ex
@@ -3,10 +3,12 @@ defmodule MobilizonWeb.Cache.ActivityPub do
   The ActivityPub related functions.
   """
 
-  alias Mobilizon.{Actors, Events, Service, Tombstone}
+  alias Mobilizon.{Actors, Events, Tombstone}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.{Comment, Event}
-  alias Service.ActivityPub
+
+  alias Mobilizon.Federation.ActivityPub.Relay
+
   alias MobilizonWeb.Router.Helpers, as: Routes
   alias MobilizonWeb.Endpoint
 
@@ -73,6 +75,6 @@ defmodule MobilizonWeb.Cache.ActivityPub do
   """
   @spec get_relay :: {:commit, Actor.t()} | {:ignore, nil}
   def get_relay do
-    Cachex.fetch(@cache, "relay_actor", &ActivityPub.Relay.get_actor/0)
+    Cachex.fetch(@cache, "relay_actor", &Relay.get_actor/0)
   end
 end
diff --git a/lib/mobilizon_web/controllers/activity_pub_controller.ex b/lib/mobilizon_web/controllers/activity_pub_controller.ex
index 51c5ecb13..72d41de5f 100644
--- a/lib/mobilizon_web/controllers/activity_pub_controller.ex
+++ b/lib/mobilizon_web/controllers/activity_pub_controller.ex
@@ -7,8 +7,9 @@ defmodule MobilizonWeb.ActivityPubController do
   use MobilizonWeb, :controller
 
   alias Mobilizon.{Actors, Actors.Actor, Config}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.Federator
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Federator
 
   alias MobilizonWeb.ActivityPub.ActorView
   alias MobilizonWeb.Cache
diff --git a/lib/mobilizon_web/controllers/web_finger_controller.ex b/lib/mobilizon_web/controllers/web_finger_controller.ex
index dca47c231..fca8074d1 100644
--- a/lib/mobilizon_web/controllers/web_finger_controller.ex
+++ b/lib/mobilizon_web/controllers/web_finger_controller.ex
@@ -7,10 +7,12 @@ defmodule MobilizonWeb.WebFingerController do
   @moduledoc """
   Handles Webfinger requests
   """
+
   use MobilizonWeb, :controller
 
+  alias Mobilizon.Federation.ActivityPub.WebFinger
+
   plug(MobilizonWeb.Plugs.Federating)
-  alias Mobilizon.Service.WebFinger
 
   @doc """
   Provides /.well-known/host-meta
diff --git a/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex b/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
index 361325848..e62c10a04 100644
--- a/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
+++ b/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
@@ -7,12 +7,15 @@ defmodule MobilizonWeb.Plugs.MappedSignatureToIdentity do
   @moduledoc """
   Get actor identity from Signature when handing fetches
   """
-  alias Mobilizon.Service.HTTPSignatures.Signature
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub.Utils
-  alias Mobilizon.Service.ActivityPub
 
   import Plug.Conn
+
+  alias Mobilizon.Actors.Actor
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Utils
+  alias Mobilizon.Federation.HTTPSignatures.Signature
+
   require Logger
 
   def init(options), do: options
diff --git a/lib/mobilizon_web/resolvers/address.ex b/lib/mobilizon_web/resolvers/address.ex
index 47d9f8475..eefc35cfb 100644
--- a/lib/mobilizon_web/resolvers/address.ex
+++ b/lib/mobilizon_web/resolvers/address.ex
@@ -2,10 +2,12 @@ defmodule MobilizonWeb.Resolvers.Address do
   @moduledoc """
   Handles the comment-related GraphQL calls
   """
-  require Logger
+
   alias Mobilizon.Addresses.Address
   alias Mobilizon.Service.Geospatial
 
+  require Logger
+
   @doc """
   Search an address
   """
diff --git a/lib/mobilizon_web/resolvers/admin.ex b/lib/mobilizon_web/resolvers/admin.ex
index 2e46bf46b..8ea664bc9 100644
--- a/lib/mobilizon_web/resolvers/admin.ex
+++ b/lib/mobilizon_web/resolvers/admin.ex
@@ -11,10 +11,11 @@ defmodule MobilizonWeb.Resolvers.Admin do
   alias Mobilizon.Events
   alias Mobilizon.Events.{Event, Comment}
   alias Mobilizon.Reports.{Note, Report}
-  alias Mobilizon.Service.Statistics
   alias Mobilizon.Users.User
+  alias Mobilizon.Service.Statistics
   alias Mobilizon.Storage.Page
-  alias Mobilizon.Service.ActivityPub.Relay
+
+  alias Mobilizon.Federation.ActivityPub.Relay
 
   def list_action_logs(
         _parent,
diff --git a/lib/mobilizon_web/resolvers/comment.ex b/lib/mobilizon_web/resolvers/comment.ex
index d61950d2e..e39099c2b 100644
--- a/lib/mobilizon_web/resolvers/comment.ex
+++ b/lib/mobilizon_web/resolvers/comment.ex
@@ -3,14 +3,15 @@ defmodule MobilizonWeb.Resolvers.Comment do
   Handles the comment-related GraphQL calls.
   """
 
+  import Mobilizon.Service.Admin.ActionLogService
+
+  alias Mobilizon.Actors
+  alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.Comment, as: CommentModel
   alias Mobilizon.Users.User
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.Actors
 
   alias MobilizonWeb.API.Comments
-  import Mobilizon.Service.Admin.ActionLogService
 
   require Logger
 
diff --git a/lib/mobilizon_web/resolvers/config.ex b/lib/mobilizon_web/resolvers/config.ex
index 44ee37f1c..a3a4d4485 100644
--- a/lib/mobilizon_web/resolvers/config.ex
+++ b/lib/mobilizon_web/resolvers/config.ex
@@ -3,9 +3,10 @@ defmodule MobilizonWeb.Resolvers.Config do
   Handles the config-related GraphQL calls.
   """
 
-  alias Mobilizon.Config
   alias Geolix.Adapter.MMDB2.Record.{Country, Location}
 
+  alias Mobilizon.Config
+
   @doc """
   Gets config.
   """
diff --git a/lib/mobilizon_web/resolvers/event.ex b/lib/mobilizon_web/resolvers/event.ex
index 8d20b53ee..bfe3030ea 100644
--- a/lib/mobilizon_web/resolvers/event.ex
+++ b/lib/mobilizon_web/resolvers/event.ex
@@ -9,9 +9,10 @@ defmodule MobilizonWeb.Resolvers.Event do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.{Event, Participant, EventParticipantStats}
-  alias Mobilizon.Service.ActivityPub.Activity
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub.Activity
+
   alias MobilizonWeb.API
   alias MobilizonWeb.Resolvers.Person
 
diff --git a/lib/mobilizon_web/resolvers/group.ex b/lib/mobilizon_web/resolvers/group.ex
index 92ea3a603..98220d670 100644
--- a/lib/mobilizon_web/resolvers/group.ex
+++ b/lib/mobilizon_web/resolvers/group.ex
@@ -5,9 +5,10 @@ defmodule MobilizonWeb.Resolvers.Group do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.{Actor, Member}
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub
+
   alias MobilizonWeb.API
   alias MobilizonWeb.Resolvers.Person
 
diff --git a/lib/mobilizon_web/resolvers/person.ex b/lib/mobilizon_web/resolvers/person.ex
index 9084ae306..82d9b172e 100644
--- a/lib/mobilizon_web/resolvers/person.ex
+++ b/lib/mobilizon_web/resolvers/person.ex
@@ -7,10 +7,11 @@ defmodule MobilizonWeb.Resolvers.Person do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.Participant
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Users
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub
+
   @doc """
   Get a person
   """
diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex
index 6e5b0c1bd..94e00cf1e 100644
--- a/lib/mobilizon_web/resolvers/user.ex
+++ b/lib/mobilizon_web/resolvers/user.ex
@@ -8,8 +8,8 @@ defmodule MobilizonWeb.Resolvers.User do
   alias Mobilizon.{Actors, Config, Users, Events}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Service.Users.{Activation, ResetPassword}
-  alias Mobilizon.Users.User
   alias Mobilizon.Storage.Repo
+  alias Mobilizon.Users.User
 
   require Logger
 
diff --git a/lib/mobilizon_web/views/activity_pub/actor_view.ex b/lib/mobilizon_web/views/activity_pub/actor_view.ex
index 284e12271..477b17ac6 100644
--- a/lib/mobilizon_web/views/activity_pub/actor_view.ex
+++ b/lib/mobilizon_web/views/activity_pub/actor_view.ex
@@ -3,8 +3,10 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Activity, Utils, Convertible}
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
 
   @private_visibility_empty_collection %{elements: [], total: 0}
 
diff --git a/lib/mobilizon_web/views/activity_pub/object_view.ex b/lib/mobilizon_web/views/activity_pub/object_view.ex
index 4ad2b9fee..f0a77dad9 100644
--- a/lib/mobilizon_web/views/activity_pub/object_view.ex
+++ b/lib/mobilizon_web/views/activity_pub/object_view.ex
@@ -1,7 +1,7 @@
 defmodule MobilizonWeb.ActivityPub.ObjectView do
   use MobilizonWeb, :view
 
-  alias Mobilizon.Service.ActivityPub.{Activity, Utils}
+  alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
 
   def render("activity.json", %{activity: %Activity{local: local, data: data} = activity}) do
     %{
diff --git a/lib/mobilizon_web/views/page_view.ex b/lib/mobilizon_web/views/page_view.ex
index 33b01cc74..e89a18277 100644
--- a/lib/mobilizon_web/views/page_view.ex
+++ b/lib/mobilizon_web/views/page_view.ex
@@ -2,14 +2,19 @@ defmodule MobilizonWeb.PageView do
   @moduledoc """
   View for our webapp
   """
+
   use MobilizonWeb, :view
+
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Tombstone
-  alias Mobilizon.Service.ActivityPub.{Convertible, Utils}
-  alias Mobilizon.Service.Metadata
-  alias Mobilizon.Service.MetadataUtils
-  alias Mobilizon.Service.Metadata.Instance
   alias Mobilizon.Events.{Comment, Event}
+  alias Mobilizon.Tombstone
+
+  alias Mobilizon.Service.Metadata
+  alias Mobilizon.Service.Metadata.Instance
+  alias Mobilizon.Service.Metadata.Utils, as: MetadataUtils
+
+  alias Mobilizon.Federation.ActivityPub.Utils
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
 
   def render("actor.activity-json", %{conn: %{assigns: %{object: %Actor{} = actor}}}) do
     actor
diff --git a/lib/service/html.ex b/lib/service/formatter/default_scrubbler.ex
similarity index 86%
rename from lib/service/html.ex
rename to lib/service/formatter/default_scrubbler.ex
index 02c4d88c3..a35b51105 100644
--- a/lib/service/html.ex
+++ b/lib/service/formatter/default_scrubbler.ex
@@ -3,21 +3,15 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/html.ex
 
-defmodule Mobilizon.Service.HTML do
+defmodule Mobilizon.Service.Formatter.DefaultScrubbler do
   @moduledoc """
-  Service to filter tags out of HTML content
+  Custom strategy to filter HTML content.
   """
-  alias HtmlSanitizeEx.Scrubber
-  alias Mobilizon.Service.HTML.Scrubber.Default
 
-  def filter_tags(html), do: Scrubber.scrub(html, Default)
-end
-
-defmodule Mobilizon.Service.HTML.Scrubber.Default do
-  @moduledoc "Custom strategy to filter HTML content"
+  alias HtmlSanitizeEx.Scrubber.Meta
 
   require HtmlSanitizeEx.Scrubber.Meta
-  alias HtmlSanitizeEx.Scrubber.Meta
+
   # credo:disable-for-previous-line
   # No idea how to fix this one…
 
diff --git a/lib/service/formatter/formatter.ex b/lib/service/formatter/formatter.ex
index 33924d68c..169139a20 100644
--- a/lib/service/formatter/formatter.ex
+++ b/lib/service/formatter/formatter.ex
@@ -10,18 +10,18 @@ defmodule Mobilizon.Service.Formatter do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.HTML
+  alias Mobilizon.Service.Formatter.HTML
 
   @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui
   @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
 
   @auto_linker_config hashtag: true,
-                      hashtag_handler: &Mobilizon.Service.Formatter.hashtag_handler/4,
+                      hashtag_handler: &__MODULE__.hashtag_handler/4,
                       mention: true,
-                      mention_handler: &Mobilizon.Service.Formatter.mention_handler/4
+                      mention_handler: &__MODULE__.mention_handler/4
 
   def escape_mention_handler("@" <> nickname = mention, buffer, _, _) do
-    case Mobilizon.Actors.get_actor_by_name(nickname) do
+    case Actors.get_actor_by_name(nickname) do
       %Actor{} ->
         # escape markdown characters with `\\`
         # (we don't want something like @user__name to be parsed by markdown)
diff --git a/lib/service/formatter/html.ex b/lib/service/formatter/html.ex
new file mode 100644
index 000000000..9eccbb217
--- /dev/null
+++ b/lib/service/formatter/html.ex
@@ -0,0 +1,17 @@
+# Portions of this file are derived from Pleroma:
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social>
+# SPDX-License-Identifier: AGPL-3.0-only
+# Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/html.ex
+
+defmodule Mobilizon.Service.Formatter.HTML do
+  @moduledoc """
+  Service to filter tags out of HTML content.
+  """
+
+  alias HtmlSanitizeEx.Scrubber
+
+  alias Mobilizon.Service.Formatter.DefaultScrubbler
+
+  def filter_tags(html), do: Scrubber.scrub(html, DefaultScrubbler)
+end
+
diff --git a/lib/service/metadata.ex b/lib/service/metadata.ex
deleted file mode 100644
index e139e503b..000000000
--- a/lib/service/metadata.ex
+++ /dev/null
@@ -1,20 +0,0 @@
-defprotocol Mobilizon.Service.Metadata do
-  @doc """
-  Build tags
-  """
-  def build_tags(entity)
-end
-
-defmodule Mobilizon.Service.MetadataUtils do
-  @moduledoc """
-  Tools to convert tags to string
-  """
-  alias Phoenix.HTML
-
-  def stringify_tags(tags) do
-    Enum.reduce(tags, "", &stringify_tag/2)
-  end
-
-  defp stringify_tag(tag, acc) when is_tuple(tag), do: acc <> HTML.safe_to_string(tag)
-  defp stringify_tag(tag, acc) when is_binary(tag), do: acc <> tag
-end
diff --git a/lib/service/metadata/metadata.ex b/lib/service/metadata/metadata.ex
new file mode 100644
index 000000000..c8642cfaf
--- /dev/null
+++ b/lib/service/metadata/metadata.ex
@@ -0,0 +1,7 @@
+defprotocol Mobilizon.Service.Metadata do
+  @doc """
+  Build tags
+  """
+
+  def build_tags(entity)
+end
diff --git a/lib/service/metadata/utils.ex b/lib/service/metadata/utils.ex
new file mode 100644
index 000000000..027a78339
--- /dev/null
+++ b/lib/service/metadata/utils.ex
@@ -0,0 +1,12 @@
+defmodule Mobilizon.Service.Metadata.Utils do
+  @moduledoc """
+  Tools to convert tags to string.
+  """
+
+  alias Phoenix.HTML
+
+  def stringify_tags(tags), do: Enum.reduce(tags, "", &stringify_tag/2)
+
+  defp stringify_tag(tag, acc) when is_tuple(tag), do: acc <> HTML.safe_to_string(tag)
+  defp stringify_tag(tag, acc) when is_binary(tag), do: acc <> tag
+end
diff --git a/mix.exs b/mix.exs
index 18e769ea7..02c248c61 100644
--- a/mix.exs
+++ b/mix.exs
@@ -182,7 +182,6 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Addresses,
         Mobilizon.Addresses.Address,
         Mobilizon.Events,
-        Mobilizon.Service.ActivityPub.Activity,
         Mobilizon.Events.Event,
         Mobilizon.Events.Comment,
         Mobilizon.Events.FeedToken,
@@ -205,7 +204,8 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Users.UserRole,
         Mobilizon.Users.Guards,
         Mobilizon.Storage.Ecto,
-        Mobilizon.Storage.Repo
+        Mobilizon.Storage.Repo,
+        Mobilizon.Federation.ActivityPub.Activity
       ],
       APIs: [
         MobilizonWeb.API.Comments,
@@ -276,19 +276,19 @@ defmodule Mobilizon.Mixfile do
         MobilizonWeb.Schema.Utils
       ],
       ActivityPub: [
+        Mobilizon.Federation.ActivityPub,
+        Mobilizon.Federation.ActivityPub.Federator,
+        Mobilizon.Federation.ActivityPub.Transmogrifier,
+        Mobilizon.Federation.ActivityPub.Utils,
+        Mobilizon.Federation.ActivityPub.WebFinger,
+        Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder,
+        Mobilizon.Federation.HTTPSignatures.Signature,
         MobilizonWeb.ActivityPub.ActorView,
         MobilizonWeb.ActivityPub.ObjectView,
         MobilizonWeb.ActivityPubController,
-        Mobilizon.Service.ActivityPub,
-        Mobilizon.Service.ActivityPub.Transmogrifier,
-        Mobilizon.Service.ActivityPub.Utils,
         MobilizonWeb.HTTPSignaturePlug,
         MobilizonWeb.WebFingerController,
-        MobilizonWeb.NodeInfoController,
-        Mobilizon.Service.HTTPSignatures.Signature,
-        Mobilizon.Service.WebFinger,
-        Mobilizon.Service.XmlBuilder,
-        Mobilizon.Service.Federator
+        MobilizonWeb.NodeInfoController
       ],
       Services: [
         Mobilizon.Service.EmailChecker,
diff --git a/test/mobilizon/service/activity_pub/activity_pub_test.exs b/test/federation/activity_pub/activity_pub_test.exs
similarity index 97%
rename from test/mobilizon/service/activity_pub/activity_pub_test.exs
rename to test/federation/activity_pub/activity_pub_test.exs
index db7683885..923f508f3 100644
--- a/test/mobilizon/service/activity_pub/activity_pub_test.exs
+++ b/test/federation/activity_pub/activity_pub_test.exs
@@ -3,19 +3,18 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/activity_pub/activity_pub_test.exs
 
-defmodule Mobilizon.Service.ActivityPub.ActivityPubTest do
+defmodule Mobilizon.Federation.ActivityPubTest do
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
-
   use Mobilizon.DataCase
 
   import Mock
-
   import Mobilizon.Factory
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.HTTPSignatures.Signature
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.HTTPSignatures.Signature
 
   @activity_pub_public_audience "https://www.w3.org/ns/activitystreams#Public"
 
diff --git a/test/mobilizon/service/activity_pub/converter/actor_test.exs b/test/federation/activity_pub/activity_stream/converter/actor_test.exs
similarity index 80%
rename from test/mobilizon/service/activity_pub/converter/actor_test.exs
rename to test/federation/activity_pub/activity_stream/converter/actor_test.exs
index edc8b0ee9..4e366e2aa 100644
--- a/test/mobilizon/service/activity_pub/converter/actor_test.exs
+++ b/test/federation/activity_pub/activity_stream/converter/actor_test.exs
@@ -1,8 +1,9 @@
-defmodule Mobilizon.Service.ActivityPub.Converter.ActorTest do
+defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.ActorTest do
   use Mobilizon.DataCase
 
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub.Converter.Actor, as: ActorConverter
+
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor, as: ActorConverter
 
   describe "actor to AS" do
     test "valid actor to as" do
diff --git a/test/mobilizon/service/activity_pub/relay_test.exs b/test/federation/activity_pub/relay_test.exs
similarity index 74%
rename from test/mobilizon/service/activity_pub/relay_test.exs
rename to test/federation/activity_pub/relay_test.exs
index 18d72405a..628868c4b 100644
--- a/test/mobilizon/service/activity_pub/relay_test.exs
+++ b/test/federation/activity_pub/relay_test.exs
@@ -2,10 +2,10 @@
 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule Mobilizon.Service.ActivityPub.RelayTest do
+defmodule Mobilizon.Federation.ActivityPub.RelayTest do
   use Mobilizon.DataCase
 
-  alias Mobilizon.Service.ActivityPub.Relay
+  alias Mobilizon.Federation.ActivityPub.Relay
 
   test "gets an actor for the relay" do
     actor = Relay.get_actor()
diff --git a/test/mobilizon/service/activity_pub/transmogrifier_test.exs b/test/federation/activity_pub/transmogrifier_test.exs
similarity index 99%
rename from test/mobilizon/service/activity_pub/transmogrifier_test.exs
rename to test/federation/activity_pub/transmogrifier_test.exs
index 1878291cd..532fa1650 100644
--- a/test/mobilizon/service/activity_pub/transmogrifier_test.exs
+++ b/test/federation/activity_pub/transmogrifier_test.exs
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/activity_pub/transmogrifier_test.exs
 
-defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
+defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
 
   use Mobilizon.DataCase
@@ -14,9 +14,11 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
   alias Mobilizon.{Actors, Events, Tombstone}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.{Comment, Event, Participant}
-  alias Mobilizon.Service.ActivityPub
-  alias Mobilizon.Service.ActivityPub.{Activity, Utils, Convertible}
-  alias Mobilizon.Service.ActivityPub.Transmogrifier
+
+  alias Mobilizon.Federation.ActivityPub
+  alias Mobilizon.Federation.ActivityPub.Utils
+  alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Transmogrifier}
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Convertible}
 
   alias MobilizonWeb.API
 
@@ -788,7 +790,7 @@ defmodule Mobilizon.Service.ActivityPub.TransmogrifierTest do
     end
 
     test "it accepts Flag activities" do
-      %Actor{url: reporter_url} = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{url: reporter_url} = Relay.get_actor()
       %Actor{url: reported_url} = reported = insert(:actor)
 
       %Comment{url: comment_url} = _comment = insert(:comment, actor: reported)
diff --git a/test/mobilizon/service/activity_pub/utils_test.exs b/test/federation/activity_pub/utils_test.exs
similarity index 93%
rename from test/mobilizon/service/activity_pub/utils_test.exs
rename to test/federation/activity_pub/utils_test.exs
index 9cf960e1a..430fd109a 100644
--- a/test/mobilizon/service/activity_pub/utils_test.exs
+++ b/test/federation/activity_pub/utils_test.exs
@@ -1,11 +1,11 @@
-defmodule Mobilizon.Service.ActivityPub.UtilsTest do
+defmodule Mobilizon.Federation.ActivityPub.UtilsTest do
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
 
   use Mobilizon.DataCase
 
   import Mobilizon.Factory
 
-  alias Mobilizon.Service.ActivityPub.Converter
+  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
 
   alias MobilizonWeb.Endpoint
   alias MobilizonWeb.Router.Helpers, as: Routes
diff --git a/test/mobilizon/service/web_finger/web_finger_test.exs b/test/federation/activity_pub/web_finger_test.exs
similarity index 95%
rename from test/mobilizon/service/web_finger/web_finger_test.exs
rename to test/federation/activity_pub/web_finger_test.exs
index e66a5df52..afe494011 100644
--- a/test/mobilizon/service/web_finger/web_finger_test.exs
+++ b/test/federation/activity_pub/web_finger_test.exs
@@ -3,12 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/web_finger/web_finger_test.exs
 
-defmodule Mobilizon.Service.WebFingerTest do
+defmodule Mobilizon.Federation.ActivityPub.WebFingerTest do
+  use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
   use Mobilizon.DataCase
-  alias Mobilizon.Service.WebFinger
+
   import Mobilizon.Factory
 
-  use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
+  alias Mobilizon.Federation.ActivityPub.WebFinger
 
   @mastodon_account "tcit@social.tcit.fr"
   @mastodon_account_username "tcit"
diff --git a/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json b/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json
index b477ec249..dc85a48f3 100644
--- a/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json
+++ b/test/fixtures/vcr_cassettes/relay/fetch_relay_follow.json
@@ -81,7 +81,7 @@
     },
     "response": {
       "binary": false,
-      "body": "# HTTPoison.Error at POST /inbox\n\nException:\n\n    ** (HTTPoison.Error) :nxdomain\n        (httpoison) lib/httpoison.ex:128: HTTPoison.request!/5\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:610: Mobilizon.Service.ActivityPub.fetch_and_prepare_actor_from_url/1\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:473: Mobilizon.Service.ActivityPub.make_actor_from_url/2\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:122: Mobilizon.Service.ActivityPub.get_or_fetch_actor_by_url/2\n        (mobilizon) lib/service/http_signatures/signature.ex:54: Mobilizon.Service.HTTPSignatures.Signature.get_public_key_for_url/1\n        (mobilizon) lib/service/http_signatures/signature.ex:74: Mobilizon.Service.HTTPSignatures.Signature.fetch_public_key/1\n        (http_signatures) lib/http_signatures/http_signatures.ex:40: HTTPSignatures.validate_conn/1\n        (mobilizon) lib/mobilizon_web/http_signature.ex:45: MobilizonWeb.HTTPSignaturePlug.call/2\n        (mobilizon) MobilizonWeb.Router.activity_pub_signature/2\n        (mobilizon) lib/mobilizon_web/router.ex:1: MobilizonWeb.Router.__pipe_through7__/1\n        (phoenix) lib/phoenix/router.ex:283: Phoenix.Router.__call__/2\n        (mobilizon) lib/mobilizon_web/endpoint.ex:1: MobilizonWeb.Endpoint.plug_builder_call/2\n        (mobilizon) lib/plug/debugger.ex:122: MobilizonWeb.Endpoint.\"call (overridable 3)\"/2\n        (mobilizon) lib/mobilizon_web/endpoint.ex:1: MobilizonWeb.Endpoint.call/2\n        (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3\n        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3\n    \n\n## Connection details\n\n### Params\n\n    %{\"@context\" => [\"https://www.w3.org/ns/activitystreams\", \"https://litepub.social/litepub/context.jsonld\", %{\"Hashtag\" => \"as:Hashtag\", \"category\" => \"sc:category\", \"ical\" => \"http://www.w3.org/2002/12/cal/ical#\", \"joinMode\" => %{\"@id\" => \"mz:joinMode\", \"@type\" => \"mz:joinModeType\"}, \"joinModeType\" => %{\"@id\" => \"mz:joinModeType\", \"@type\" => \"rdfs:Class\"}, \"maximumAttendeeCapacity\" => \"sc:maximumAttendeeCapacity\", \"mz\" => \"https://joinmobilizon.org/ns#\", \"repliesModerationOption\" => %{\"@id\" => \"mz:repliesModerationOption\", \"@type\" => \"mz:repliesModerationOptionType\"}, \"repliesModerationOptionType\" => %{\"@id\" => \"mz:repliesModerationOptionType\", \"@type\" => \"rdfs:Class\"}, \"sc\" => \"http://schema.org#\", \"uuid\" => \"sc:identifier\"}], \"actor\" => \"http://mobilizon.test/relay\", \"cc\" => [\"https://www.w3.org/ns/activitystreams#Public\"], \"id\" => \"http://mobilizon.test/follow/b7791977-2a75-4715-815b-6e7125065b71\", \"object\" => \"http://mobilizon1.com/relay\", \"to\" => [\"http://mobilizon1.com/relay\"], \"type\" => \"Follow\"}\n\n### Request info\n\n  * URI: http://mobilizon1.com:80/inbox\n  * Query string: \n\n### Headers\n  \n  * connection: upgrade\n  * content-length: 912\n  * content-type: application/activity+json\n  * date: Fri, 13 Dec 2019 09:41:41 GMT\n  * digest: SHA-256=ibNFcsnBeCCjWZo9We60tKfbRN3el0WCMVdOxtuC1cg=\n  * host: mobilizon1.com\n  * signature: keyId=\"http://mobilizon.test/relay#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) content-length date digest host\",signature=\"WbyGHT/WdvdRpWek8uCGHrFSblLpg+Iq802R5S2cjNj035OKpxRmu1r8u9Qr5KGIKgZn6LHt9YmB+PNlwsubPtTSkJpE8AAUDMHLKgCrH7A5Q6x6GlARl5bHNo4QtOxkXvnEbn31xfNDNp70QqZb/emw95TnELYUlMLZds0qYutT8U4WdDhSWcVytQmKJWNZXxEj+KlMDUaxag3lGscJ/HY0F+yGNov7FHthid1Y4LTGFsp/tismnMTlba12NH/kXPHtduNsX8uxFslM2ODwqAaospTGEpXmr9CPgbNy7626qgYaR2RdB/fYlCayLI4JJIlH8gOdocGHPrWNtVEHaQ==\"\n  * user-agent: hackney/1.15.2\n  * x-forwarded-for: 127.0.0.1\n  * x-real-ip: 127.0.0.1\n\n### Session\n\n    %{}\n",
+      "body": "# HTTPoison.Error at POST /inbox\n\nException:\n\n    ** (HTTPoison.Error) :nxdomain\n        (httpoison) lib/httpoison.ex:128: HTTPoison.request!/5\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:610: Mobilizon.Service.ActivityPub.fetch_and_prepare_actor_from_url/1\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:473: Mobilizon.Service.ActivityPub.make_actor_from_url/2\n        (mobilizon) lib/service/activity_pub/activity_pub.ex:122: Mobilizon.Service.ActivityPub.get_or_fetch_actor_by_url/2\n        (mobilizon) lib/service/http_signatures/signature.ex:54: Mobilizon.Federation.HTTPSignatures.Signature.get_public_key_for_url/1\n        (mobilizon) lib/service/http_signatures/signature.ex:74: Mobilizon.Federation.HTTPSignatures.Signature.fetch_public_key/1\n        (http_signatures) lib/http_signatures/http_signatures.ex:40: HTTPSignatures.validate_conn/1\n        (mobilizon) lib/mobilizon_web/http_signature.ex:45: MobilizonWeb.HTTPSignaturePlug.call/2\n        (mobilizon) MobilizonWeb.Router.activity_pub_signature/2\n        (mobilizon) lib/mobilizon_web/router.ex:1: MobilizonWeb.Router.__pipe_through7__/1\n        (phoenix) lib/phoenix/router.ex:283: Phoenix.Router.__call__/2\n        (mobilizon) lib/mobilizon_web/endpoint.ex:1: MobilizonWeb.Endpoint.plug_builder_call/2\n        (mobilizon) lib/plug/debugger.ex:122: MobilizonWeb.Endpoint.\"call (overridable 3)\"/2\n        (mobilizon) lib/mobilizon_web/endpoint.ex:1: MobilizonWeb.Endpoint.call/2\n        (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3\n        (cowboy) /home/tcit/dev/frama/mobilizon/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3\n        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3\n    \n\n## Connection details\n\n### Params\n\n    %{\"@context\" => [\"https://www.w3.org/ns/activitystreams\", \"https://litepub.social/litepub/context.jsonld\", %{\"Hashtag\" => \"as:Hashtag\", \"category\" => \"sc:category\", \"ical\" => \"http://www.w3.org/2002/12/cal/ical#\", \"joinMode\" => %{\"@id\" => \"mz:joinMode\", \"@type\" => \"mz:joinModeType\"}, \"joinModeType\" => %{\"@id\" => \"mz:joinModeType\", \"@type\" => \"rdfs:Class\"}, \"maximumAttendeeCapacity\" => \"sc:maximumAttendeeCapacity\", \"mz\" => \"https://joinmobilizon.org/ns#\", \"repliesModerationOption\" => %{\"@id\" => \"mz:repliesModerationOption\", \"@type\" => \"mz:repliesModerationOptionType\"}, \"repliesModerationOptionType\" => %{\"@id\" => \"mz:repliesModerationOptionType\", \"@type\" => \"rdfs:Class\"}, \"sc\" => \"http://schema.org#\", \"uuid\" => \"sc:identifier\"}], \"actor\" => \"http://mobilizon.test/relay\", \"cc\" => [\"https://www.w3.org/ns/activitystreams#Public\"], \"id\" => \"http://mobilizon.test/follow/b7791977-2a75-4715-815b-6e7125065b71\", \"object\" => \"http://mobilizon1.com/relay\", \"to\" => [\"http://mobilizon1.com/relay\"], \"type\" => \"Follow\"}\n\n### Request info\n\n  * URI: http://mobilizon1.com:80/inbox\n  * Query string: \n\n### Headers\n  \n  * connection: upgrade\n  * content-length: 912\n  * content-type: application/activity+json\n  * date: Fri, 13 Dec 2019 09:41:41 GMT\n  * digest: SHA-256=ibNFcsnBeCCjWZo9We60tKfbRN3el0WCMVdOxtuC1cg=\n  * host: mobilizon1.com\n  * signature: keyId=\"http://mobilizon.test/relay#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) content-length date digest host\",signature=\"WbyGHT/WdvdRpWek8uCGHrFSblLpg+Iq802R5S2cjNj035OKpxRmu1r8u9Qr5KGIKgZn6LHt9YmB+PNlwsubPtTSkJpE8AAUDMHLKgCrH7A5Q6x6GlARl5bHNo4QtOxkXvnEbn31xfNDNp70QqZb/emw95TnELYUlMLZds0qYutT8U4WdDhSWcVytQmKJWNZXxEj+KlMDUaxag3lGscJ/HY0F+yGNov7FHthid1Y4LTGFsp/tismnMTlba12NH/kXPHtduNsX8uxFslM2ODwqAaospTGEpXmr9CPgbNy7626qgYaR2RdB/fYlCayLI4JJIlH8gOdocGHPrWNtVEHaQ==\"\n  * user-agent: hackney/1.15.2\n  * x-forwarded-for: 127.0.0.1\n  * x-real-ip: 127.0.0.1\n\n### Session\n\n    %{}\n",
       "headers": {
         "Server": "nginx/1.16.1",
         "Date": "Fri, 13 Dec 2019 09:41:41 GMT",
@@ -98,4 +98,4 @@
       "type": "ok"
     }
   }
-]
\ No newline at end of file
+]
diff --git a/test/mobilizon/actors/actors_test.exs b/test/mobilizon/actors/actors_test.exs
index d829ecfd5..07d0945bd 100644
--- a/test/mobilizon/actors/actors_test.exs
+++ b/test/mobilizon/actors/actors_test.exs
@@ -9,9 +9,10 @@ defmodule Mobilizon.ActorsTest do
   alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
   alias Mobilizon.Events.{Event, Comment}
   alias Mobilizon.Media.File, as: FileModel
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Storage.Page
 
+  alias Mobilizon.Federation.ActivityPub
+
   describe "actors" do
     @valid_attrs %{
       summary: "some description",
diff --git a/test/mobilizon_web/api/report_test.exs b/test/mobilizon_web/api/report_test.exs
index db7d3f9bd..03cfaa432 100644
--- a/test/mobilizon_web/api/report_test.exs
+++ b/test/mobilizon_web/api/report_test.exs
@@ -6,15 +6,16 @@ defmodule MobilizonWeb.API.ReportTest do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events.{Comment, Event}
   alias Mobilizon.Reports.{Note, Report}
-  alias Mobilizon.Service.ActivityPub.Activity
   alias Mobilizon.Users
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub.{Activity, Relay}
+
   alias MobilizonWeb.API.Reports
 
   describe "reports" do
     test "creates a report on a event" do
-      %Actor{url: relay_reporter_url} = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{url: relay_reporter_url} = Relay.get_actor()
       %Actor{id: reporter_id} = insert(:actor)
       %Actor{id: reported_id, url: reported_url} = reported = insert(:actor)
 
@@ -44,7 +45,7 @@ defmodule MobilizonWeb.API.ReportTest do
     end
 
     test "creates a report on several comments" do
-      %Actor{url: relay_reporter_url} = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{url: relay_reporter_url} = Relay.get_actor()
       %Actor{id: reporter_id} = insert(:actor)
       %Actor{id: reported_id, url: reported_url} = reported = insert(:actor)
 
@@ -79,7 +80,7 @@ defmodule MobilizonWeb.API.ReportTest do
     end
 
     test "creates a report that gets federated" do
-      %Actor{url: relay_reporter_url} = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{url: relay_reporter_url} = Relay.get_actor()
       %Actor{id: reporter_id} = insert(:actor)
       %Actor{id: reported_id, url: reported_url} = reported = insert(:actor)
 
diff --git a/test/mobilizon_web/api/search_test.exs b/test/mobilizon_web/api/search_test.exs
index ee19fdca3..e3d800bc5 100644
--- a/test/mobilizon_web/api/search_test.exs
+++ b/test/mobilizon_web/api/search_test.exs
@@ -7,9 +7,10 @@ defmodule MobilizonWeb.API.SearchTest do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.Event
-  alias Mobilizon.Service.ActivityPub
   alias Mobilizon.Storage.Page
 
+  alias Mobilizon.Federation.ActivityPub
+
   alias MobilizonWeb.API.Search
 
   test "search an user by username" do
diff --git a/test/mobilizon_web/controllers/activity_pub_controller_test.exs b/test/mobilizon_web/controllers/activity_pub_controller_test.exs
index 6c1b9a3d2..e53487df1 100644
--- a/test/mobilizon_web/controllers/activity_pub_controller_test.exs
+++ b/test/mobilizon_web/controllers/activity_pub_controller_test.exs
@@ -12,7 +12,8 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
 
   alias Mobilizon.{Actors, Config}
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.ActivityPub
+
+  alias Mobilizon.Federation.ActivityPub
 
   alias MobilizonWeb.ActivityPub.ActorView
   alias MobilizonWeb.Endpoint
@@ -318,7 +319,7 @@ defmodule MobilizonWeb.ActivityPubControllerTest do
   #    test "it returns the following in a collection", %{conn: conn} do
   #      actor = insert(:actor)
   #      actor2 = insert(:actor)
-  #      Mobilizon.Service.ActivityPub.follow(actor, actor2)
+  #      Mobilizon.Federation.ActivityPub.follow(actor, actor2)
 
   #      result =
   #        conn
diff --git a/test/mobilizon_web/controllers/webfinger_controller_test.exs b/test/mobilizon_web/controllers/webfinger_controller_test.exs
index d980d1be9..8ecc9da91 100644
--- a/test/mobilizon_web/controllers/webfinger_controller_test.exs
+++ b/test/mobilizon_web/controllers/webfinger_controller_test.exs
@@ -3,14 +3,17 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/web_finger/web_finger_test.exs
 
-defmodule MobilizonWeb.WebFingerTest do
+defmodule MobilizonWeb.WebFingerControllerTest do
   use MobilizonWeb.ConnCase
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.WebFinger
+
   import Mobilizon.Factory
 
+  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Federation.ActivityPub.WebFinger
+
   setup_all do
     Mobilizon.Config.put([:instance, :federating], true)
+
     :ok
   end
 
diff --git a/test/mobilizon_web/resolvers/admin_resolver_test.exs b/test/mobilizon_web/resolvers/admin_resolver_test.exs
index 7e6cf996e..30c9d0362 100644
--- a/test/mobilizon_web/resolvers/admin_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/admin_resolver_test.exs
@@ -8,6 +8,8 @@ defmodule MobilizonWeb.Resolvers.AdminResolverTest do
   alias Mobilizon.Reports.{Note, Report}
   alias Mobilizon.Users.User
 
+  alias Mobilizon.Federation.ActivityPub.Relay
+
   alias MobilizonWeb.AbsintheHelpers
   alias MobilizonWeb.API
 
@@ -135,7 +137,7 @@ defmodule MobilizonWeb.Resolvers.AdminResolverTest do
           name: "I am an instance actor"
         )
 
-      %Actor{} = relay_actor = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{} = relay_actor = Relay.get_actor()
       insert(:follower, actor: follower_actor, target_actor: relay_actor)
 
       query = """
@@ -182,7 +184,7 @@ defmodule MobilizonWeb.Resolvers.AdminResolverTest do
           name: "I am an instance actor"
         )
 
-      %Actor{} = relay_actor = Mobilizon.Service.ActivityPub.Relay.get_actor()
+      %Actor{} = relay_actor = Relay.get_actor()
       insert(:follower, actor: relay_actor, target_actor: following_actor)
 
       query = """
diff --git a/test/mobilizon/service/admin/action_log_service_test.exs b/test/service/admin/action_log_service_test.exs
similarity index 100%
rename from test/mobilizon/service/admin/action_log_service_test.exs
rename to test/service/admin/action_log_service_test.exs
diff --git a/test/mobilizon/service/export/icalendar_test.exs b/test/service/export/icalendar_test.exs
similarity index 100%
rename from test/mobilizon/service/export/icalendar_test.exs
rename to test/service/export/icalendar_test.exs
diff --git a/test/mobilizon/service/formatter/formatter_test.exs b/test/service/formatter/formatter_test.exs
similarity index 100%
rename from test/mobilizon/service/formatter/formatter_test.exs
rename to test/service/formatter/formatter_test.exs
diff --git a/test/mobilizon/service/geospatial/addok_test.exs b/test/service/geospatial/addok_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/addok_test.exs
rename to test/service/geospatial/addok_test.exs
diff --git a/test/mobilizon/service/geospatial/geospatial_test.exs b/test/service/geospatial/geospatial_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/geospatial_test.exs
rename to test/service/geospatial/geospatial_test.exs
diff --git a/test/mobilizon/service/geospatial/google_maps_test.exs b/test/service/geospatial/google_maps_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/google_maps_test.exs
rename to test/service/geospatial/google_maps_test.exs
diff --git a/test/mobilizon/service/geospatial/map_quest_test.exs b/test/service/geospatial/map_quest_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/map_quest_test.exs
rename to test/service/geospatial/map_quest_test.exs
diff --git a/test/mobilizon/service/geospatial/nominatim_test.exs b/test/service/geospatial/nominatim_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/nominatim_test.exs
rename to test/service/geospatial/nominatim_test.exs
diff --git a/test/mobilizon/service/geospatial/photon_test.exs b/test/service/geospatial/photon_test.exs
similarity index 100%
rename from test/mobilizon/service/geospatial/photon_test.exs
rename to test/service/geospatial/photon_test.exs
diff --git a/test/mobilizon/service/users/tools.exs b/test/service/users/tools.exs
similarity index 100%
rename from test/mobilizon/service/users/tools.exs
rename to test/service/users/tools.exs
diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs
index cdcedddb0..5e64dfdd5 100644
--- a/test/tasks/relay_test.exs
+++ b/test/tasks/relay_test.exs
@@ -9,7 +9,8 @@ defmodule Mix.Tasks.Mobilizon.RelayTest do
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.{Actor, Follower}
-  alias Mobilizon.Service.ActivityPub.Relay
+
+  alias Mobilizon.Federation.ActivityPub.Relay
 
   describe "running follow" do
     test "relay is followed" do

From d1251280c57c7b27bb02426aec66d5c7f447c98f Mon Sep 17 00:00:00 2001
From: rustra <rustra@riseup.net>
Date: Wed, 22 Jan 2020 22:40:40 +0100
Subject: [PATCH 2/4] Put HTTPSignatures, WebFinger and ActivityStream
 alongside with ActivityPub

---
 lib/federation/activity_pub/activity_pub.ex          | 10 +++++-----
 lib/federation/activity_pub/relay.ex                 |  3 ++-
 lib/federation/activity_pub/transmogrifier.ex        |  2 +-
 lib/federation/activity_pub/utils.ex                 |  2 +-
 .../{activity_pub => }/activity_stream/converter.ex  |  2 +-
 .../activity_stream/converter/actor.ex               |  6 +++---
 .../activity_stream/converter/address.ex             |  4 ++--
 .../activity_stream/converter/comment.ex             |  8 ++++----
 .../activity_stream/converter/event.ex               | 12 ++++++------
 .../activity_stream/converter/flag.ex                |  6 +++---
 .../activity_stream/converter/follower.ex            |  6 +++---
 .../activity_stream/converter/participant.ex         |  6 +++---
 .../activity_stream/converter/picture.ex             | 10 ++--------
 .../activity_stream/converter/tombstone.ex           |  6 +++---
 .../activity_stream/converter/utils.ex               |  6 ++----
 .../activity_stream/convertible.ex                   |  2 +-
 .../{activity_pub => }/http_signatures/signature.ex  |  0
 .../{activity_pub => }/web_finger/web_finger.ex      |  4 ++--
 .../{activity_pub => }/web_finger/xml_builder.ex     |  2 +-
 .../controllers/web_finger_controller.ex             |  2 +-
 lib/mobilizon_web/views/activity_pub/actor_view.ex   |  2 +-
 lib/mobilizon_web/views/page_view.ex                 |  2 +-
 mix.exs                                              |  4 ++--
 test/federation/activity_pub/transmogrifier_test.exs |  2 +-
 test/federation/activity_pub/utils_test.exs          |  2 +-
 .../activity_stream/converter/actor_test.exs         |  4 ++--
 .../{activity_pub => }/web_finger_test.exs           |  4 ++--
 .../controllers/webfinger_controller_test.exs        |  2 +-
 28 files changed, 57 insertions(+), 64 deletions(-)
 rename lib/federation/{activity_pub => }/activity_stream/converter.ex (76%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/actor.ex (92%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/address.ex (93%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/comment.ex (92%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/event.ex (91%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/flag.ex (91%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/follower.ex (79%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/participant.ex (72%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/picture.ex (86%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/tombstone.ex (76%)
 rename lib/federation/{activity_pub => }/activity_stream/converter/utils.ex (95%)
 rename lib/federation/{activity_pub => }/activity_stream/convertible.ex (67%)
 rename lib/federation/{activity_pub => }/http_signatures/signature.ex (100%)
 rename lib/federation/{activity_pub => }/web_finger/web_finger.ex (96%)
 rename lib/federation/{activity_pub => }/web_finger/xml_builder.ex (94%)
 rename test/federation/{activity_pub => }/activity_stream/converter/actor_test.exs (81%)
 rename test/federation/{activity_pub => }/web_finger_test.exs (95%)

diff --git a/lib/federation/activity_pub/activity_pub.ex b/lib/federation/activity_pub/activity_pub.ex
index d54eb00c7..78191b105 100644
--- a/lib/federation/activity_pub/activity_pub.ex
+++ b/lib/federation/activity_pub/activity_pub.ex
@@ -22,13 +22,13 @@ defmodule Mobilizon.Federation.ActivityPub do
     Federator,
     Relay,
     Transmogrifier,
-    Visibility,
-    WebFinger
+    Visibility
   }
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
   alias Mobilizon.Federation.HTTPSignatures.Signature
+  alias Mobilizon.Federation.WebFinger
 
   alias MobilizonWeb.API.Utils, as: APIUtils
   alias MobilizonWeb.Email.{Admin, Mailer}
@@ -38,7 +38,7 @@ defmodule Mobilizon.Federation.ActivityPub do
   @doc """
   Wraps an object into an activity
   """
-  @spec create_activity(map(), boolean()) :: {:ok, %Activity{}}
+  @spec create_activity(map, boolean) :: {:ok, Activity.t()}
   def create_activity(map, local \\ true) when is_map(map) do
     with map <- lazy_put_activity_defaults(map) do
       {:ok,
diff --git a/lib/federation/activity_pub/relay.ex b/lib/federation/activity_pub/relay.ex
index 111699de1..6a0fec7ef 100644
--- a/lib/federation/activity_pub/relay.ex
+++ b/lib/federation/activity_pub/relay.ex
@@ -12,7 +12,8 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do
   alias Mobilizon.Actors.{Actor, Follower}
 
   alias Mobilizon.Federation.ActivityPub
-  alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier, WebFinger}
+  alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier}
+  alias Mobilizon.Federation.WebFinger
 
   alias MobilizonWeb.API.Follows
 
diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex
index 486df279c..481fbe88e 100644
--- a/lib/federation/activity_pub/transmogrifier.ex
+++ b/lib/federation/activity_pub/transmogrifier.ex
@@ -15,7 +15,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
 
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
 
   alias MobilizonWeb.Email.Participation
 
diff --git a/lib/federation/activity_pub/utils.ex b/lib/federation/activity_pub/utils.ex
index 53485908e..016e8f21b 100644
--- a/lib/federation/activity_pub/utils.ex
+++ b/lib/federation/activity_pub/utils.ex
@@ -13,7 +13,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
   alias Mobilizon.Media.Picture
 
   alias Mobilizon.Federation.ActivityPub.{Activity, Federator, Relay}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
+  alias Mobilizon.Federation.ActivityStream.Converter
   alias Mobilizon.Federation.HTTPSignatures
 
   require Logger
diff --git a/lib/federation/activity_pub/activity_stream/converter.ex b/lib/federation/activity_stream/converter.ex
similarity index 76%
rename from lib/federation/activity_pub/activity_stream/converter.ex
rename to lib/federation/activity_stream/converter.ex
index 39c21b4c9..4398304f5 100644
--- a/lib/federation/activity_pub/activity_stream/converter.ex
+++ b/lib/federation/activity_stream/converter.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter do
+defmodule Mobilizon.Federation.ActivityStream.Converter do
   @moduledoc """
   Converter behaviour.
 
diff --git a/lib/federation/activity_pub/activity_stream/converter/actor.ex b/lib/federation/activity_stream/converter/actor.ex
similarity index 92%
rename from lib/federation/activity_pub/activity_stream/converter/actor.ex
rename to lib/federation/activity_stream/converter/actor.ex
index f28da9e17..5468c6de1 100644
--- a/lib/federation/activity_pub/activity_stream/converter/actor.ex
+++ b/lib/federation/activity_stream/converter/actor.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
   @moduledoc """
   Actor converter.
 
@@ -9,12 +9,12 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor do
   alias Mobilizon.Actors.Actor, as: ActorModel
 
   alias Mobilizon.Federation.ActivityPub.Utils
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
 
   @behaviour Converter
 
   defimpl Convertible, for: ActorModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor, as: ActorConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Actor, as: ActorConverter
 
     defdelegate model_to_as(actor), to: ActorConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/address.ex b/lib/federation/activity_stream/converter/address.ex
similarity index 93%
rename from lib/federation/activity_pub/activity_stream/converter/address.ex
rename to lib/federation/activity_stream/converter/address.ex
index b24296fae..87b679ac7 100644
--- a/lib/federation/activity_pub/activity_stream/converter/address.ex
+++ b/lib/federation/activity_stream/converter/address.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Address do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Address do
   @moduledoc """
   Address converter.
 
@@ -8,7 +8,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Address do
 
   alias Mobilizon.Addresses.Address, as: AddressModel
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
+  alias Mobilizon.Federation.ActivityStream.Converter
 
   @behaviour Converter
 
diff --git a/lib/federation/activity_pub/activity_stream/converter/comment.ex b/lib/federation/activity_stream/converter/comment.ex
similarity index 92%
rename from lib/federation/activity_pub/activity_stream/converter/comment.ex
rename to lib/federation/activity_stream/converter/comment.ex
index b9e7d43fc..064dfd74d 100644
--- a/lib/federation/activity_pub/activity_stream/converter/comment.ex
+++ b/lib/federation/activity_stream/converter/comment.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Comment do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Comment do
   @moduledoc """
   Comment converter.
 
@@ -13,15 +13,15 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Comment do
 
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.Visibility
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
 
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: CommentModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Comment, as: CommentConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Comment, as: CommentConverter
 
     defdelegate model_to_as(comment), to: CommentConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/event.ex b/lib/federation/activity_stream/converter/event.ex
similarity index 91%
rename from lib/federation/activity_pub/activity_stream/converter/event.ex
rename to lib/federation/activity_stream/converter/event.ex
index 76c31ad61..0a6adfd7b 100644
--- a/lib/federation/activity_pub/activity_stream/converter/event.ex
+++ b/lib/federation/activity_stream/converter/event.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Event do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
   @moduledoc """
   Event converter.
 
@@ -13,17 +13,17 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Event do
   alias Mobilizon.Media.Picture
 
   alias Mobilizon.Federation.ActivityPub
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Address, as: AddressConverter
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Picture, as: PictureConverter
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils, as: ConverterUtils
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.Converter.Address, as: AddressConverter
+  alias Mobilizon.Federation.ActivityStream.Converter.Picture, as: PictureConverter
+  alias Mobilizon.Federation.ActivityStream.Converter.Utils, as: ConverterUtils
 
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: EventModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Event, as: EventConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Event, as: EventConverter
 
     defdelegate model_to_as(event), to: EventConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/flag.ex b/lib/federation/activity_stream/converter/flag.ex
similarity index 91%
rename from lib/federation/activity_pub/activity_stream/converter/flag.ex
rename to lib/federation/activity_stream/converter/flag.ex
index bd50a8031..b604ddb03 100644
--- a/lib/federation/activity_pub/activity_stream/converter/flag.ex
+++ b/lib/federation/activity_stream/converter/flag.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Flag do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Flag do
   @moduledoc """
   Flag converter.
 
@@ -14,13 +14,13 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Flag do
   alias Mobilizon.Events.Event
   alias Mobilizon.Reports.Report
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
   alias Mobilizon.Federation.ActivityPub.Relay
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
 
   @behaviour Converter
 
   defimpl Convertible, for: Report do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Flag, as: FlagConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Flag, as: FlagConverter
 
     defdelegate model_to_as(report), to: FlagConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/follower.ex b/lib/federation/activity_stream/converter/follower.ex
similarity index 79%
rename from lib/federation/activity_pub/activity_stream/converter/follower.ex
rename to lib/federation/activity_stream/converter/follower.ex
index d280a3f69..028a393ee 100644
--- a/lib/federation/activity_pub/activity_stream/converter/follower.ex
+++ b/lib/federation/activity_stream/converter/follower.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Follower do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Follower do
   @moduledoc """
   Participant converter.
 
@@ -9,10 +9,10 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Follower do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Actors.Follower, as: FollowerModel
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
+  alias Mobilizon.Federation.ActivityStream.Convertible
 
   defimpl Convertible, for: FollowerModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Follower,
+    alias Mobilizon.Federation.ActivityStream.Converter.Follower,
       as: FollowerConverter
 
     defdelegate model_to_as(follower), to: FollowerConverter
diff --git a/lib/federation/activity_pub/activity_stream/converter/participant.ex b/lib/federation/activity_stream/converter/participant.ex
similarity index 72%
rename from lib/federation/activity_pub/activity_stream/converter/participant.ex
rename to lib/federation/activity_stream/converter/participant.ex
index 51eb26ea6..1581b6547 100644
--- a/lib/federation/activity_pub/activity_stream/converter/participant.ex
+++ b/lib/federation/activity_stream/converter/participant.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Participant do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Participant do
   @moduledoc """
   Participant converter.
 
@@ -8,10 +8,10 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Participant
 
   alias Mobilizon.Events.Participant, as: ParticipantModel
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
+  alias Mobilizon.Federation.ActivityStream.Convertible
 
   defimpl Convertible, for: ParticipantModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Participant, as: ParticipantConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Participant, as: ParticipantConverter
 
     defdelegate model_to_as(participant), to: ParticipantConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/picture.ex b/lib/federation/activity_stream/converter/picture.ex
similarity index 86%
rename from lib/federation/activity_pub/activity_stream/converter/picture.ex
rename to lib/federation/activity_stream/converter/picture.ex
index 2c4b0894c..f2f29d1d0 100644
--- a/lib/federation/activity_pub/activity_stream/converter/picture.ex
+++ b/lib/federation/activity_stream/converter/picture.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Picture do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Picture do
   @moduledoc """
   Picture converter.
 
@@ -33,13 +33,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Picture do
       )
       when is_bitstring(picture_url) do
     with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(picture_url),
-         {:ok,
-          %{
-            name: name,
-            url: url,
-            content_type: content_type,
-            size: size
-          }} <-
+         {:ok, %{name: name, url: url, content_type: content_type, size: size}} <-
            MobilizonWeb.Upload.store(%{body: body, name: name}),
          {:picture_exists, nil} <- {:picture_exists, Mobilizon.Media.get_picture_by_url(url)} do
       Mobilizon.Media.create_picture(%{
diff --git a/lib/federation/activity_pub/activity_stream/converter/tombstone.ex b/lib/federation/activity_stream/converter/tombstone.ex
similarity index 76%
rename from lib/federation/activity_pub/activity_stream/converter/tombstone.ex
rename to lib/federation/activity_stream/converter/tombstone.ex
index d782c0bf9..d0712286f 100644
--- a/lib/federation/activity_pub/activity_stream/converter/tombstone.ex
+++ b/lib/federation/activity_stream/converter/tombstone.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Tombstone do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Tombstone do
   @moduledoc """
   Comment converter.
 
@@ -7,14 +7,14 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Tombstone do
 
   alias Mobilizon.Tombstone, as: TombstoneModel
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Converter, Convertible}
+  alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
 
   require Logger
 
   @behaviour Converter
 
   defimpl Convertible, for: TombstoneModel do
-    alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Tombstone, as: TombstoneConverter
+    alias Mobilizon.Federation.ActivityStream.Converter.Tombstone, as: TombstoneConverter
 
     defdelegate model_to_as(comment), to: TombstoneConverter
   end
diff --git a/lib/federation/activity_pub/activity_stream/converter/utils.ex b/lib/federation/activity_stream/converter/utils.ex
similarity index 95%
rename from lib/federation/activity_pub/activity_stream/converter/utils.ex
rename to lib/federation/activity_stream/converter/utils.ex
index 06c656603..1783ef81d 100644
--- a/lib/federation/activity_pub/activity_stream/converter/utils.ex
+++ b/lib/federation/activity_stream/converter/utils.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils do
+defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
   @moduledoc """
   Various utils for converters.
   """
@@ -29,9 +29,7 @@ defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Utils do
   end
 
   def fetch_address(%{id: id}) do
-    with {id, ""} <- Integer.parse(id) do
-      %{id: id}
-    end
+    with {id, ""} <- Integer.parse(id), do: %{id: id}
   end
 
   def fetch_address(address) when is_map(address) do
diff --git a/lib/federation/activity_pub/activity_stream/convertible.ex b/lib/federation/activity_stream/convertible.ex
similarity index 67%
rename from lib/federation/activity_pub/activity_stream/convertible.ex
rename to lib/federation/activity_stream/convertible.ex
index cb27a76cc..cf6e2dfc1 100644
--- a/lib/federation/activity_pub/activity_stream/convertible.ex
+++ b/lib/federation/activity_stream/convertible.ex
@@ -1,4 +1,4 @@
-defprotocol Mobilizon.Federation.ActivityPub.ActivityStream.Convertible do
+defprotocol Mobilizon.Federation.ActivityStream.Convertible do
   @moduledoc """
   Convertible protocol.
   """
diff --git a/lib/federation/activity_pub/http_signatures/signature.ex b/lib/federation/http_signatures/signature.ex
similarity index 100%
rename from lib/federation/activity_pub/http_signatures/signature.ex
rename to lib/federation/http_signatures/signature.ex
diff --git a/lib/federation/activity_pub/web_finger/web_finger.ex b/lib/federation/web_finger/web_finger.ex
similarity index 96%
rename from lib/federation/activity_pub/web_finger/web_finger.ex
rename to lib/federation/web_finger/web_finger.ex
index 3e9459a54..bf71c384b 100644
--- a/lib/federation/activity_pub/web_finger/web_finger.ex
+++ b/lib/federation/web_finger/web_finger.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/web_finger/web_finger.ex
 
-defmodule Mobilizon.Federation.ActivityPub.WebFinger do
+defmodule Mobilizon.Federation.WebFinger do
   @moduledoc """
   Performs the WebFinger requests and responses (JSON only).
   """
@@ -11,7 +11,7 @@ defmodule Mobilizon.Federation.ActivityPub.WebFinger do
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
 
-  alias Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder
+  alias Mobilizon.Federation.WebFinger.XmlBuilder
 
   require Jason
   require Logger
diff --git a/lib/federation/activity_pub/web_finger/xml_builder.ex b/lib/federation/web_finger/xml_builder.ex
similarity index 94%
rename from lib/federation/activity_pub/web_finger/xml_builder.ex
rename to lib/federation/web_finger/xml_builder.ex
index 0c7cf45e6..76cc2cbea 100644
--- a/lib/federation/activity_pub/web_finger/xml_builder.ex
+++ b/lib/federation/web_finger/xml_builder.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/xml_builder.ex
 
-defmodule Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder do
+defmodule Mobilizon.Federation.WebFinger.XmlBuilder do
   @moduledoc """
   Builds XRD for WebFinger host_meta.
   """
diff --git a/lib/mobilizon_web/controllers/web_finger_controller.ex b/lib/mobilizon_web/controllers/web_finger_controller.ex
index fca8074d1..6e96dc487 100644
--- a/lib/mobilizon_web/controllers/web_finger_controller.ex
+++ b/lib/mobilizon_web/controllers/web_finger_controller.ex
@@ -10,7 +10,7 @@ defmodule MobilizonWeb.WebFingerController do
 
   use MobilizonWeb, :controller
 
-  alias Mobilizon.Federation.ActivityPub.WebFinger
+  alias Mobilizon.Federation.WebFinger
 
   plug(MobilizonWeb.Plugs.Federating)
 
diff --git a/lib/mobilizon_web/views/activity_pub/actor_view.ex b/lib/mobilizon_web/views/activity_pub/actor_view.ex
index 477b17ac6..5d207a8cb 100644
--- a/lib/mobilizon_web/views/activity_pub/actor_view.ex
+++ b/lib/mobilizon_web/views/activity_pub/actor_view.ex
@@ -6,7 +6,7 @@ defmodule MobilizonWeb.ActivityPub.ActorView do
 
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
+  alias Mobilizon.Federation.ActivityStream.Convertible
 
   @private_visibility_empty_collection %{elements: [], total: 0}
 
diff --git a/lib/mobilizon_web/views/page_view.ex b/lib/mobilizon_web/views/page_view.ex
index e89a18277..8a0cc3832 100644
--- a/lib/mobilizon_web/views/page_view.ex
+++ b/lib/mobilizon_web/views/page_view.ex
@@ -14,7 +14,7 @@ defmodule MobilizonWeb.PageView do
   alias Mobilizon.Service.Metadata.Utils, as: MetadataUtils
 
   alias Mobilizon.Federation.ActivityPub.Utils
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Convertible
+  alias Mobilizon.Federation.ActivityStream.Convertible
 
   def render("actor.activity-json", %{conn: %{assigns: %{object: %Actor{} = actor}}}) do
     actor
diff --git a/mix.exs b/mix.exs
index 02c248c61..6d92edd14 100644
--- a/mix.exs
+++ b/mix.exs
@@ -280,9 +280,9 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Federation.ActivityPub.Federator,
         Mobilizon.Federation.ActivityPub.Transmogrifier,
         Mobilizon.Federation.ActivityPub.Utils,
-        Mobilizon.Federation.ActivityPub.WebFinger,
-        Mobilizon.Federation.ActivityPub.WebFinger.XmlBuilder,
         Mobilizon.Federation.HTTPSignatures.Signature,
+        Mobilizon.Federation.WebFinger,
+        Mobilizon.Federation.WebFinger.XmlBuilder,
         MobilizonWeb.ActivityPub.ActorView,
         MobilizonWeb.ActivityPub.ObjectView,
         MobilizonWeb.ActivityPubController,
diff --git a/test/federation/activity_pub/transmogrifier_test.exs b/test/federation/activity_pub/transmogrifier_test.exs
index 532fa1650..07065c4cc 100644
--- a/test/federation/activity_pub/transmogrifier_test.exs
+++ b/test/federation/activity_pub/transmogrifier_test.exs
@@ -18,7 +18,7 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.Utils
   alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Transmogrifier}
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.{Convertible}
+  alias Mobilizon.Federation.ActivityStream.{Convertible}
 
   alias MobilizonWeb.API
 
diff --git a/test/federation/activity_pub/utils_test.exs b/test/federation/activity_pub/utils_test.exs
index 430fd109a..949635893 100644
--- a/test/federation/activity_pub/utils_test.exs
+++ b/test/federation/activity_pub/utils_test.exs
@@ -5,7 +5,7 @@ defmodule Mobilizon.Federation.ActivityPub.UtilsTest do
 
   import Mobilizon.Factory
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter
+  alias Mobilizon.Federation.ActivityStream.Converter
 
   alias MobilizonWeb.Endpoint
   alias MobilizonWeb.Router.Helpers, as: Routes
diff --git a/test/federation/activity_pub/activity_stream/converter/actor_test.exs b/test/federation/activity_stream/converter/actor_test.exs
similarity index 81%
rename from test/federation/activity_pub/activity_stream/converter/actor_test.exs
rename to test/federation/activity_stream/converter/actor_test.exs
index 4e366e2aa..886845cbf 100644
--- a/test/federation/activity_pub/activity_stream/converter/actor_test.exs
+++ b/test/federation/activity_stream/converter/actor_test.exs
@@ -1,9 +1,9 @@
-defmodule Mobilizon.Federation.ActivityPub.ActivityStream.Converter.ActorTest do
+defmodule Mobilizon.Federation.ActivityStream.Converter.ActorTest do
   use Mobilizon.DataCase
 
   alias Mobilizon.Actors.Actor
 
-  alias Mobilizon.Federation.ActivityPub.ActivityStream.Converter.Actor, as: ActorConverter
+  alias Mobilizon.Federation.ActivityStream.Converter.Actor, as: ActorConverter
 
   describe "actor to AS" do
     test "valid actor to as" do
diff --git a/test/federation/activity_pub/web_finger_test.exs b/test/federation/web_finger_test.exs
similarity index 95%
rename from test/federation/activity_pub/web_finger_test.exs
rename to test/federation/web_finger_test.exs
index afe494011..4d3337f8d 100644
--- a/test/federation/activity_pub/web_finger_test.exs
+++ b/test/federation/web_finger_test.exs
@@ -3,13 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/test/web/web_finger/web_finger_test.exs
 
-defmodule Mobilizon.Federation.ActivityPub.WebFingerTest do
+defmodule Mobilizon.Federation.WebFingerTest do
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
   use Mobilizon.DataCase
 
   import Mobilizon.Factory
 
-  alias Mobilizon.Federation.ActivityPub.WebFinger
+  alias Mobilizon.Federation.WebFinger
 
   @mastodon_account "tcit@social.tcit.fr"
   @mastodon_account_username "tcit"
diff --git a/test/mobilizon_web/controllers/webfinger_controller_test.exs b/test/mobilizon_web/controllers/webfinger_controller_test.exs
index 8ecc9da91..11739330a 100644
--- a/test/mobilizon_web/controllers/webfinger_controller_test.exs
+++ b/test/mobilizon_web/controllers/webfinger_controller_test.exs
@@ -9,7 +9,7 @@ defmodule MobilizonWeb.WebFingerControllerTest do
   import Mobilizon.Factory
 
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Federation.ActivityPub.WebFinger
+  alias Mobilizon.Federation.WebFinger
 
   setup_all do
     Mobilizon.Config.put([:instance, :federating], true)

From 8ca5c0b320b3f8100548614f79047eaca60b2446 Mon Sep 17 00:00:00 2001
From: rustra <rustra@riseup.net>
Date: Thu, 23 Jan 2020 00:55:07 +0100
Subject: [PATCH 3/4] Separate Web modules related to Federation

---
 lib/federation/activity_pub/activity_pub.ex   |  36 ++----
 .../controllers/activity_pub_controller.ex    |   9 +-
 .../plugs/federating.ex                       |   3 +-
 .../plugs}/http_signature.ex                  |   5 +-
 .../plugs/mapped_signature_to_identity.ex     |   0
 .../views}/actor_view.ex                      |   0
 .../views}/object_view.ex                     |   0
 lib/mix/tasks/mobilizon/setup_search.ex       |   9 +-
 lib/mobilizon/actors/actors.ex                |   4 +-
 lib/mobilizon/events/events.ex                |  15 ++-
 lib/mobilizon/users/guards.ex                 |   9 ++
 lib/mobilizon/users/user.ex                   |   5 +-
 lib/mobilizon_web/api/reports.ex              |   2 +-
 .../controllers/web_finger_controller.ex      |   2 +-
 .../email/checker.ex}                         |   2 +-
 lib/mobilizon_web/email/event.ex              |  44 ++++++-
 lib/mobilizon_web/email/user.ex               | 109 +++++++++++++++++-
 lib/mobilizon_web/plugs/uploaded_media.ex     |   9 +-
 lib/mobilizon_web/resolvers/comment.ex        |   2 +-
 lib/mobilizon_web/resolvers/event.ex          |   2 +-
 lib/mobilizon_web/resolvers/user.ex           |  19 ++-
 lib/mobilizon_web/router.ex                   |   8 +-
 .../{action_log_service.ex => action_log.ex}  |   5 +-
 lib/service/events/tools.ex                   |  50 --------
 lib/service/{ => statistics}/statistics.ex    |   4 +-
 lib/service/users/activation.ex               |  46 --------
 lib/service/users/reset_password.ex           |  62 ----------
 lib/service/users/tools.ex                    |  43 -------
 .../{background_worker.ex => background.ex}   |   4 +-
 ...build_search_worker.ex => build_search.ex} |   4 +-
 .../workers/{worker_helper.ex => helper.ex}   |   9 +-
 mix.exs                                       |   2 +-
 .../plugs/federating_plug_test.exs            |  12 +-
 ...mapped_identity_to_signature_plug_test.exs |   3 +-
 .../{ => web_finger}/web_finger_test.exs      |   0
 test/mobilizon/actors/actors_test.exs         |   3 +-
 test/mobilizon/events/events_test.exs         |   8 +-
 .../users/guards_test.exs}                    |   2 +-
 .../resolvers/event_resolver_test.exs         |  19 +--
 .../resolvers/person_resolver_test.exs        |  12 +-
 .../resolvers/search_resolver_test.exs        |  28 ++---
 ...g_service_test.exs => action_log_test.exs} |   6 +-
 42 files changed, 279 insertions(+), 337 deletions(-)
 rename lib/{mobilizon_web => federation}/controllers/activity_pub_controller.ex (94%)
 rename lib/{mobilizon_web => federation}/plugs/federating.ex (92%)
 rename lib/{mobilizon_web => federation/plugs}/http_signature.ex (95%)
 rename lib/{mobilizon_web => federation}/plugs/mapped_signature_to_identity.ex (100%)
 rename lib/{mobilizon_web/views/activity_pub => federation/views}/actor_view.ex (100%)
 rename lib/{mobilizon_web/views/activity_pub => federation/views}/object_view.ex (100%)
 create mode 100644 lib/mobilizon/users/guards.ex
 rename lib/{service/email_checker.ex => mobilizon_web/email/checker.ex} (90%)
 rename lib/service/admin/{action_log_service.ex => action_log.ex} (91%)
 delete mode 100644 lib/service/events/tools.ex
 rename lib/service/{ => statistics}/statistics.ex (93%)
 delete mode 100644 lib/service/users/activation.ex
 delete mode 100644 lib/service/users/reset_password.ex
 delete mode 100644 lib/service/users/tools.ex
 rename lib/service/workers/{background_worker.ex => background.ex} (72%)
 rename lib/service/workers/{build_search_worker.ex => build_search.ex} (92%)
 rename lib/service/workers/{worker_helper.ex => helper.ex} (85%)
 rename test/{mobilizon_web => federation}/plugs/federating_plug_test.exs (74%)
 rename test/{mobilizon_web => federation}/plugs/mapped_identity_to_signature_plug_test.exs (96%)
 rename test/federation/{ => web_finger}/web_finger_test.exs (100%)
 rename test/{service/users/tools.exs => mobilizon/users/guards_test.exs} (94%)
 rename test/service/admin/{action_log_service_test.exs => action_log_test.exs} (89%)

diff --git a/lib/federation/activity_pub/activity_pub.ex b/lib/federation/activity_pub/activity_pub.ex
index 78191b105..2bf6edefb 100644
--- a/lib/federation/activity_pub/activity_pub.ex
+++ b/lib/federation/activity_pub/activity_pub.ex
@@ -662,9 +662,7 @@ defmodule Mobilizon.Federation.ActivityPub do
     {:ok, comments, total_comments} = Events.list_public_comments_for_actor(actor, page, limit)
 
     event_activities = Enum.map(events, &event_to_activity/1)
-
     comment_activities = Enum.map(comments, &comment_to_activity/1)
-
     activities = event_activities ++ comment_activities
 
     %{elements: activities, total: total_events + total_comments}
@@ -740,13 +738,8 @@ defmodule Mobilizon.Federation.ActivityPub do
   defp check_for_tombstones(%{url: url}), do: Tombstone.find_tombstone(url)
   defp check_for_tombstones(_), do: nil
 
-  @spec update_event(Event.t(), map(), map()) ::
-          {:ok, Event.t(), Activity.t()} | any()
-  defp update_event(
-         %Event{} = old_event,
-         args,
-         additional
-       ) do
+  @spec update_event(Event.t(), map(), map()) :: {:ok, Event.t(), Activity.t()} | any()
+  defp update_event(%Event{} = old_event, args, additional) do
     with args <- prepare_args_for_event(args),
          {:ok, %Event{} = new_event} <- Events.update_event(old_event, args),
          {:ok, true} <- Cachex.del(:activity_pub, "event_#{new_event.uuid}"),
@@ -763,8 +756,7 @@ defmodule Mobilizon.Federation.ActivityPub do
     end
   end
 
-  @spec update_actor(Actor.t(), map(), map()) ::
-          {:ok, Actor.t(), Activity.t()} | any()
+  @spec update_actor(Actor.t(), map, map) :: {:ok, Actor.t(), Activity.t()} | any
   defp update_actor(%Actor{} = old_actor, args, additional) do
     with {:ok, %Actor{} = new_actor} <- Actors.update_actor(old_actor, args),
          actor_as_data <- Convertible.model_to_as(new_actor),
@@ -777,12 +769,8 @@ defmodule Mobilizon.Federation.ActivityPub do
     end
   end
 
-  @spec accept_follow(Follower.t(), map()) ::
-          {:ok, Follower.t(), Activity.t()} | any()
-  defp accept_follow(
-         %Follower{} = follower,
-         additional
-       ) do
+  @spec accept_follow(Follower.t(), map) :: {:ok, Follower.t(), Activity.t()} | any
+  defp accept_follow(%Follower{} = follower, additional) do
     with {:ok, %Follower{} = follower} <- Actors.update_follower(follower, %{approved: true}),
          follower_as_data <- Convertible.model_to_as(follower),
          update_data <-
@@ -804,12 +792,8 @@ defmodule Mobilizon.Federation.ActivityPub do
     end
   end
 
-  @spec accept_join(Participant.t(), map()) ::
-          {:ok, Participant.t(), Activity.t()} | any()
-  defp accept_join(
-         %Participant{} = participant,
-         additional
-       ) do
+  @spec accept_join(Participant.t(), map) :: {:ok, Participant.t(), Activity.t()} | any
+  defp accept_join(%Participant{} = participant, additional) do
     with {:ok, %Participant{} = participant} <-
            Events.update_participant(participant, %{role: :participant}),
          Absinthe.Subscription.publish(MobilizonWeb.Endpoint, participant.actor,
@@ -834,8 +818,7 @@ defmodule Mobilizon.Federation.ActivityPub do
     end
   end
 
-  @spec reject_join(Participant.t(), map()) ::
-          {:ok, Participant.t(), Activity.t()} | any()
+  @spec reject_join(Participant.t(), map()) :: {:ok, Participant.t(), Activity.t()} | any()
   defp reject_join(%Participant{} = participant, additional) do
     with {:ok, %Participant{} = participant} <-
            Events.update_participant(participant, %{approved: false, role: :rejected}),
@@ -866,8 +849,7 @@ defmodule Mobilizon.Federation.ActivityPub do
     end
   end
 
-  @spec reject_follow(Follower.t(), map()) ::
-          {:ok, Follower.t(), Activity.t()} | any()
+  @spec reject_follow(Follower.t(), map()) :: {:ok, Follower.t(), Activity.t()} | any()
   defp reject_follow(%Follower{} = follower, additional) do
     with {:ok, %Follower{} = follower} <- Actors.delete_follower(follower),
          follower_as_data <- Convertible.model_to_as(follower),
diff --git a/lib/mobilizon_web/controllers/activity_pub_controller.ex b/lib/federation/controllers/activity_pub_controller.ex
similarity index 94%
rename from lib/mobilizon_web/controllers/activity_pub_controller.ex
rename to lib/federation/controllers/activity_pub_controller.ex
index 72d41de5f..2893ab0d4 100644
--- a/lib/mobilizon_web/controllers/activity_pub_controller.ex
+++ b/lib/federation/controllers/activity_pub_controller.ex
@@ -3,10 +3,11 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/activity_pub_controller.ex
 
-defmodule MobilizonWeb.ActivityPubController do
-  use MobilizonWeb, :controller
+defmodule Mobilizon.Federation.ActivityPubController do
+  use Mobilizon.Federation, :controller
 
-  alias Mobilizon.{Actors, Actors.Actor, Config}
+  alias Mobilizon.{Actors, Config}
+  alias Mobilizon.Actors.Actor
 
   alias Mobilizon.Federation.ActivityPub
   alias Mobilizon.Federation.ActivityPub.Federator
@@ -18,7 +19,7 @@ defmodule MobilizonWeb.ActivityPubController do
 
   action_fallback(:errors)
 
-  plug(MobilizonWeb.Plugs.Federating when action in [:inbox, :relay])
+  plug(Mobilizon.Federation.Plugs.Federating when action in [:inbox, :relay])
   plug(:relay_active? when action in [:relay])
 
   def relay_active?(conn, _) do
diff --git a/lib/mobilizon_web/plugs/federating.ex b/lib/federation/plugs/federating.ex
similarity index 92%
rename from lib/mobilizon_web/plugs/federating.ex
rename to lib/federation/plugs/federating.ex
index 282c8ab2c..8af7f8e91 100644
--- a/lib/mobilizon_web/plugs/federating.ex
+++ b/lib/federation/plugs/federating.ex
@@ -3,10 +3,11 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule MobilizonWeb.Plugs.Federating do
+defmodule Mobilizon.Federation.Plugs.Federating do
   @moduledoc """
   Restrict ActivityPub routes when not federating
   """
+
   import Plug.Conn
 
   def init(options) do
diff --git a/lib/mobilizon_web/http_signature.ex b/lib/federation/plugs/http_signature.ex
similarity index 95%
rename from lib/mobilizon_web/http_signature.ex
rename to lib/federation/plugs/http_signature.ex
index 5e0580d16..1075eba54 100644
--- a/lib/mobilizon_web/http_signature.ex
+++ b/lib/federation/plugs/http_signature.ex
@@ -3,14 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/plugs/http_signature.ex
 
-defmodule MobilizonWeb.HTTPSignaturePlug do
+defmodule Mobilizon.Federation.Plugs.HTTPSignatures do
   @moduledoc """
-  # HTTPSignaturePlug
-
   Plug to check HTTP Signatures on every incoming request
   """
 
   import Plug.Conn
+
   require Logger
 
   def init(options) do
diff --git a/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex b/lib/federation/plugs/mapped_signature_to_identity.ex
similarity index 100%
rename from lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
rename to lib/federation/plugs/mapped_signature_to_identity.ex
diff --git a/lib/mobilizon_web/views/activity_pub/actor_view.ex b/lib/federation/views/actor_view.ex
similarity index 100%
rename from lib/mobilizon_web/views/activity_pub/actor_view.ex
rename to lib/federation/views/actor_view.ex
diff --git a/lib/mobilizon_web/views/activity_pub/object_view.ex b/lib/federation/views/object_view.ex
similarity index 100%
rename from lib/mobilizon_web/views/activity_pub/object_view.ex
rename to lib/federation/views/object_view.ex
diff --git a/lib/mix/tasks/mobilizon/setup_search.ex b/lib/mix/tasks/mobilizon/setup_search.ex
index 76439e98f..4633a2a76 100644
--- a/lib/mix/tasks/mobilizon/setup_search.ex
+++ b/lib/mix/tasks/mobilizon/setup_search.ex
@@ -7,11 +7,12 @@ defmodule Mix.Tasks.Mobilizon.SetupSearch do
 
   use Mix.Task
 
-  alias Mobilizon.Service.Workers.BuildSearchWorker
-  alias Mobilizon.Storage.Repo
-  alias Mobilizon.Events.Event
   import Ecto.Query
 
+  alias Mobilizon.Events.Event
+  alias Mobilizon.Service.Workers
+  alias Mobilizon.Storage.Repo
+
   require Logger
 
   @shortdoc "Insert search data"
@@ -30,7 +31,7 @@ defmodule Mix.Tasks.Mobilizon.SetupSearch do
   end
 
   defp insert_search_event([%Event{url: url} = event | events], nb_events) do
-    case BuildSearchWorker.insert_search_event(event) do
+    case Workers.BuildSearch.insert_search_event(event) do
       {:ok, _} ->
         Logger.debug("Added event #{url} to the search")
 
diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex
index 44d977ecf..44c562d7e 100644
--- a/lib/mobilizon/actors/actors.ex
+++ b/lib/mobilizon/actors/actors.ex
@@ -11,7 +11,7 @@ defmodule Mobilizon.Actors do
   alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
   alias Mobilizon.{Crypto, Events}
   alias Mobilizon.Media.File
-  alias Mobilizon.Service.Workers.BackgroundWorker
+  alias Mobilizon.Service.Workers
   alias Mobilizon.Storage.{Page, Repo}
 
   alias Mobilizon.Federation.ActivityPub
@@ -229,7 +229,7 @@ defmodule Mobilizon.Actors do
   end
 
   def delete_actor(%Actor{} = actor) do
-    BackgroundWorker.enqueue("delete_actor", %{"actor_id" => actor.id})
+    Workers.Background.enqueue("delete_actor", %{"actor_id" => actor.id})
   end
 
   @doc """
diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 0427c638c..94bcfef9b 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -13,7 +13,6 @@ defmodule Mobilizon.Events do
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Addresses.Address
-  alias Mobilizon.Service.Workers.BuildSearchWorker
 
   alias Mobilizon.Events.{
     Comment,
@@ -27,9 +26,12 @@ defmodule Mobilizon.Events do
     Track
   }
 
+  alias Mobilizon.Service.Workers
   alias Mobilizon.Storage.{Page, Repo}
   alias Mobilizon.Users.User
 
+  alias MobilizonWeb.Email
+
   defenum(EventVisibility, :event_visibility, [
     :public,
     :unlisted,
@@ -264,7 +266,7 @@ defmodule Mobilizon.Events do
     with {:ok, %{insert: %Event{} = event}} <- do_create_event(attrs),
          %Event{} = event <- Repo.preload(event, @event_preloads) do
       unless event.draft,
-        do: BuildSearchWorker.enqueue(:insert_search_event, %{"event_id" => event.id})
+        do: Workers.BuildSearch.enqueue(:insert_search_event, %{"event_id" => event.id})
 
       {:ok, event}
     else
@@ -308,10 +310,7 @@ defmodule Mobilizon.Events do
            Event.update_changeset(Repo.preload(old_event, :tags), attrs),
          {:ok, %{update: %Event{} = new_event}} <-
            Multi.new()
-           |> Multi.update(
-             :update,
-             changeset
-           )
+           |> Multi.update(:update, changeset)
            |> Multi.run(:write, fn _repo, %{update: %Event{draft: draft} = event} ->
              with {:was_draft, true} <- {:was_draft, old_draft == true && draft == false},
                   {:ok, %Participant{} = participant} <-
@@ -332,14 +331,14 @@ defmodule Mobilizon.Events do
            |> Repo.transaction() do
       Cachex.del(:ics, "event_#{new_event.uuid}")
 
-      Mobilizon.Service.Events.Tool.calculate_event_diff_and_send_notifications(
+      Email.Events.calculate_event_diff_and_send_notifications(
         old_event,
         new_event,
         changes
       )
 
       unless new_event.draft,
-        do: BuildSearchWorker.enqueue(:update_search_event, %{"event_id" => new_event.id})
+        do: BuildSearch.enqueue(:update_search_event, %{"event_id" => new_event.id})
 
       {:ok, Repo.preload(new_event, @event_preloads)}
     end
diff --git a/lib/mobilizon/users/guards.ex b/lib/mobilizon/users/guards.ex
new file mode 100644
index 000000000..d9821dfaf
--- /dev/null
+++ b/lib/mobilizon/users/guards.ex
@@ -0,0 +1,9 @@
+defmodule Mobilizon.Users.Guards do
+  @moduledoc """
+  Guards for users
+  """
+
+  defguard is_admin(role) when is_atom(role) and role == :administrator
+
+  defguard is_moderator(role) when is_atom(role) and role in [:administrator, :moderator]
+end
diff --git a/lib/mobilizon/users/user.ex b/lib/mobilizon/users/user.ex
index a87875158..919daf928 100644
--- a/lib/mobilizon/users/user.ex
+++ b/lib/mobilizon/users/user.ex
@@ -10,9 +10,10 @@ defmodule Mobilizon.Users.User do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Crypto
   alias Mobilizon.Events.FeedToken
-  alias Mobilizon.Service.EmailChecker
   alias Mobilizon.Users.UserRole
 
+  alias MobilizonWeb.Email
+
   @type t :: %__MODULE__{
           email: String.t(),
           password_hash: String.t(),
@@ -176,7 +177,7 @@ defmodule Mobilizon.Users.User do
 
     case changeset do
       %Ecto.Changeset{valid?: true, changes: %{email: email}} ->
-        case EmailChecker.valid?(email) do
+        case Email.Checker.valid?(email) do
           false ->
             add_error(changeset, :email, "Email doesn't fit required format")
 
diff --git a/lib/mobilizon_web/api/reports.ex b/lib/mobilizon_web/api/reports.ex
index 8fd7f68c2..582ae4312 100644
--- a/lib/mobilizon_web/api/reports.ex
+++ b/lib/mobilizon_web/api/reports.ex
@@ -3,7 +3,7 @@ defmodule MobilizonWeb.API.Reports do
   API for Reports.
   """
 
-  import Mobilizon.Service.Admin.ActionLogService
+  import Mobilizon.Service.Admin.ActionLog
 
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Reports, as: ReportsAction
diff --git a/lib/mobilizon_web/controllers/web_finger_controller.ex b/lib/mobilizon_web/controllers/web_finger_controller.ex
index 6e96dc487..d831ede32 100644
--- a/lib/mobilizon_web/controllers/web_finger_controller.ex
+++ b/lib/mobilizon_web/controllers/web_finger_controller.ex
@@ -12,7 +12,7 @@ defmodule MobilizonWeb.WebFingerController do
 
   alias Mobilizon.Federation.WebFinger
 
-  plug(MobilizonWeb.Plugs.Federating)
+  plug(Mobilizon.Federation.Plugs.Federating)
 
   @doc """
   Provides /.well-known/host-meta
diff --git a/lib/service/email_checker.ex b/lib/mobilizon_web/email/checker.ex
similarity index 90%
rename from lib/service/email_checker.ex
rename to lib/mobilizon_web/email/checker.ex
index f92ec33c1..17ee1b1d6 100644
--- a/lib/service/email_checker.ex
+++ b/lib/mobilizon_web/email/checker.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.EmailChecker do
+defmodule MobilizonWeb.Email.Checker do
   @moduledoc """
   Provides a function to test emails against a "not so bad" regex.
   """
diff --git a/lib/mobilizon_web/email/event.ex b/lib/mobilizon_web/email/event.ex
index a568521a0..9ea5b9851 100644
--- a/lib/mobilizon_web/email/event.ex
+++ b/lib/mobilizon_web/email/event.ex
@@ -9,11 +9,16 @@ defmodule MobilizonWeb.Email.Event do
 
   import MobilizonWeb.Gettext
 
-  alias Mobilizon.Events.Event
   alias Mobilizon.Actors.Actor
+  alias Mobilizon.Events
+  alias Mobilizon.Events.Event
+  alias Mobilizon.Storage.Repo
   alias Mobilizon.Users.User
+
   alias MobilizonWeb.Email
 
+  @important_changes [:title, :begins_on, :ends_on, :status]
+
   @spec event_updated(User.t(), Actor.t(), Event.t(), Event.t(), list(), String.t()) ::
           Bamboo.Email.t()
   def event_updated(
@@ -40,4 +45,41 @@ defmodule MobilizonWeb.Email.Event do
     |> assign(:subject, subject)
     |> render(:event_updated)
   end
+
+  def calculate_event_diff_and_send_notifications(
+        %Event{} = old_event,
+        %Event{id: event_id} = event,
+        changes
+      ) do
+    important = MapSet.new(@important_changes)
+
+    diff =
+      changes
+      |> Map.keys()
+      |> MapSet.new()
+      |> MapSet.intersection(important)
+
+    if MapSet.size(diff) > 0 do
+      Repo.transaction(fn ->
+        event_id
+        |> Events.list_local_emails_user_participants_for_event_query()
+        |> Repo.stream()
+        |> Enum.to_list()
+        |> Enum.each(
+          &send_notification_for_event_update_to_participant(&1, old_event, event, diff)
+        )
+      end)
+    end
+  end
+
+  defp send_notification_for_event_update_to_participant(
+         {%Actor{} = actor, %User{locale: locale} = user},
+         %Event{} = old_event,
+         %Event{} = event,
+         diff
+       ) do
+    user
+    |> Email.Event.event_updated(actor, old_event, event, diff, locale)
+    |> Email.Mailer.deliver_later()
+  end
 end
diff --git a/lib/mobilizon_web/email/user.ex b/lib/mobilizon_web/email/user.ex
index b331e8951..131cd4f5b 100644
--- a/lib/mobilizon_web/email/user.ex
+++ b/lib/mobilizon_web/email/user.ex
@@ -9,11 +9,14 @@ defmodule MobilizonWeb.Email.User do
 
   import MobilizonWeb.Gettext
 
-  alias Mobilizon.Config
+  alias Mobilizon.{Config, Crypto, Users}
+  alias Mobilizon.Storage.Repo
   alias Mobilizon.Users.User
 
   alias MobilizonWeb.Email
 
+  require Logger
+
   @spec confirmation_email(User.t(), String.t()) :: Bamboo.Email.t()
   def confirmation_email(
         %User{email: email, confirmation_token: confirmation_token},
@@ -53,4 +56,108 @@ defmodule MobilizonWeb.Email.User do
     |> assign(:subject, subject)
     |> render(:password_reset)
   end
+
+  def check_confirmation_token(token) when is_binary(token) do
+    with %User{} = user <- Users.get_user_by_activation_token(token),
+         {:ok, %User{} = user} <-
+           Users.update_user(user, %{
+             "confirmed_at" => DateTime.utc_now() |> DateTime.truncate(:second),
+             "confirmation_sent_at" => nil,
+             "confirmation_token" => nil
+           }) do
+      Logger.info("User #{user.email} has been confirmed")
+      {:ok, user}
+    else
+      _err ->
+        {:error, :invalid_token}
+    end
+  end
+
+  def resend_confirmation_email(%User{} = user, locale \\ "en") do
+    with :ok <- we_can_send_email(user, :confirmation_sent_at),
+         {:ok, user} <-
+           Users.update_user(user, %{
+             "confirmation_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
+           }) do
+      send_confirmation_email(user, locale)
+      Logger.info("Sent confirmation email again to #{user.email}")
+      {:ok, user.email}
+    end
+  end
+
+  def send_confirmation_email(%User{} = user, locale \\ "en") do
+    user
+    |> Email.User.confirmation_email(locale)
+    |> Email.Mailer.deliver_later()
+  end
+
+  @doc """
+  Check that the provided token is correct and update provided password
+  """
+  @spec check_reset_password_token(String.t(), String.t()) :: tuple
+  def check_reset_password_token(password, token) do
+    with %User{} = user <- Users.get_user_by_reset_password_token(token),
+         {:ok, %User{} = user} <-
+           Repo.update(
+             User.password_reset_changeset(user, %{
+               "password" => password,
+               "reset_password_sent_at" => nil,
+               "reset_password_token" => nil
+             })
+           ) do
+      {:ok, user}
+    else
+      {:error, %Ecto.Changeset{errors: [password: {"registration.error.password_too_short", _}]}} ->
+        {:error,
+         "The password you have choosen is too short. Please make sure your password contains at least 6 charaters."}
+
+      _err ->
+        {:error,
+         "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."}
+    end
+  end
+
+  @doc """
+  Send the email reset password, if it's not too soon since the last send
+  """
+  @spec send_password_reset_email(User.t(), String.t()) :: tuple
+  def send_password_reset_email(%User{} = user, locale \\ "en") do
+    with :ok <- we_can_send_email(user, :reset_password_sent_at),
+         {:ok, %User{} = user_updated} <-
+           Repo.update(
+             User.send_password_reset_changeset(user, %{
+               "reset_password_token" => Crypto.random_string(30),
+               "reset_password_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
+             })
+           ) do
+      mail =
+        user_updated
+        |> Email.User.reset_password_email(locale)
+        |> Email.Mailer.deliver_later()
+
+      {:ok, mail}
+    else
+      {:error, reason} -> {:error, reason}
+    end
+  end
+
+  @spec we_can_send_email(User.t(), atom) :: :ok | {:error, :email_too_soon}
+  defp we_can_send_email(%User{} = user, key) do
+    case Map.get(user, key) do
+      nil ->
+        :ok
+
+      _ ->
+        case Timex.before?(
+              Timex.shift(Map.get(user, key), hours: 1),
+              DateTime.utc_now() |> DateTime.truncate(:second)
+            ) do
+          true ->
+            :ok
+
+          false ->
+            {:error, :email_too_soon}
+        end
+    end
+  end
 end
diff --git a/lib/mobilizon_web/plugs/uploaded_media.ex b/lib/mobilizon_web/plugs/uploaded_media.ex
index b8d648fb0..78f72dd59 100644
--- a/lib/mobilizon_web/plugs/uploaded_media.ex
+++ b/lib/mobilizon_web/plugs/uploaded_media.ex
@@ -35,8 +35,7 @@ defmodule MobilizonWeb.Plugs.UploadedMedia do
         %{query_params: %{"name" => name}} = conn ->
           name = String.replace(name, "\"", "\\\"")
 
-          conn
-          |> put_resp_header("content-disposition", "filename=\"#{name}\"")
+          put_resp_header(conn, "content-disposition", "filename=\"#{name}\"")
 
         conn ->
           conn
@@ -77,11 +76,7 @@ defmodule MobilizonWeb.Plugs.UploadedMedia do
   end
 
   defp get_media(conn, {:url, url}, true, _) do
-    conn
-    |> MobilizonWeb.ReverseProxy.call(
-      url,
-      Config.get([Mobilizon.Upload, :proxy_opts], [])
-    )
+    MobilizonWeb.ReverseProxy.call(conn, url, Config.get([Mobilizon.Upload, :proxy_opts], []))
   end
 
   defp get_media(conn, {:url, url}, _, _) do
diff --git a/lib/mobilizon_web/resolvers/comment.ex b/lib/mobilizon_web/resolvers/comment.ex
index e39099c2b..094f18d37 100644
--- a/lib/mobilizon_web/resolvers/comment.ex
+++ b/lib/mobilizon_web/resolvers/comment.ex
@@ -3,7 +3,7 @@ defmodule MobilizonWeb.Resolvers.Comment do
   Handles the comment-related GraphQL calls.
   """
 
-  import Mobilizon.Service.Admin.ActionLogService
+  import Mobilizon.Service.Admin.ActionLog
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
diff --git a/lib/mobilizon_web/resolvers/event.ex b/lib/mobilizon_web/resolvers/event.ex
index bfe3030ea..086cdc296 100644
--- a/lib/mobilizon_web/resolvers/event.ex
+++ b/lib/mobilizon_web/resolvers/event.ex
@@ -3,7 +3,7 @@ defmodule MobilizonWeb.Resolvers.Event do
   Handles the event-related GraphQL calls.
   """
 
-  import Mobilizon.Service.Admin.ActionLogService
+  import Mobilizon.Service.Admin.ActionLog
 
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex
index 94e00cf1e..6d09f88db 100644
--- a/lib/mobilizon_web/resolvers/user.ex
+++ b/lib/mobilizon_web/resolvers/user.ex
@@ -7,10 +7,11 @@ defmodule MobilizonWeb.Resolvers.User do
 
   alias Mobilizon.{Actors, Config, Users, Events}
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.Users.{Activation, ResetPassword}
   alias Mobilizon.Storage.Repo
   alias Mobilizon.Users.User
 
+  alias MobilizonWeb.Email
+
   require Logger
 
   @doc """
@@ -118,7 +119,7 @@ defmodule MobilizonWeb.Resolvers.User do
   def create_user(_parent, args, _resolution) do
     with :registration_ok <- check_registration_config(args),
          {:ok, %User{} = user} <- Users.register(args) do
-      Activation.send_confirmation_email(user, Map.get(args, :locale, "en"))
+      Email.User.send_confirmation_email(user, Map.get(args, :locale, "en"))
       {:ok, user}
     else
       :registration_closed ->
@@ -161,7 +162,7 @@ defmodule MobilizonWeb.Resolvers.User do
   """
   def validate_user(_parent, %{token: token}, _resolution) do
     with {:check_confirmation_token, {:ok, %User{} = user}} <-
-           {:check_confirmation_token, Activation.check_confirmation_token(token)},
+           {:check_confirmation_token, Email.User.check_confirmation_token(token)},
          {:get_actor, actor} <- {:get_actor, Users.get_actor_for_user(user)},
          {:ok, %{access_token: access_token, refresh_token: refresh_token}} <-
            Users.generate_tokens(user) do
@@ -187,7 +188,7 @@ defmodule MobilizonWeb.Resolvers.User do
     with {:ok, %User{locale: locale} = user} <-
            Users.get_user_by_email(Map.get(args, :email), false),
          {:ok, email} <-
-           Activation.resend_confirmation_email(user, Map.get(args, :locale, locale)) do
+           Email.User.resend_confirmation_email(user, Map.get(args, :locale, locale)) do
       {:ok, email}
     else
       {:error, :user_not_found} ->
@@ -205,7 +206,7 @@ defmodule MobilizonWeb.Resolvers.User do
     with email <- Map.get(args, :email),
          {:ok, %User{locale: locale} = user} <- Users.get_user_by_email(email, true),
          {:ok, %Bamboo.Email{} = _email_html} <-
-           ResetPassword.send_password_reset_email(user, Map.get(args, :locale, locale)) do
+           Email.User.send_password_reset_email(user, Map.get(args, :locale, locale)) do
       {:ok, email}
     else
       {:error, :user_not_found} ->
@@ -222,7 +223,7 @@ defmodule MobilizonWeb.Resolvers.User do
   """
   def reset_password(_parent, %{password: password, token: token}, _resolution) do
     with {:ok, %User{} = user} <-
-           ResetPassword.check_reset_password_token(password, token),
+           Email.User.check_reset_password_token(password, token),
          {:ok, %{access_token: access_token, refresh_token: refresh_token}} <-
            Users.authenticate(%{user: user, password: password}) do
       {:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}}
@@ -233,11 +234,7 @@ defmodule MobilizonWeb.Resolvers.User do
   def change_default_actor(
         _parent,
         %{preferred_username: username},
-        %{
-          context: %{
-            current_user: user
-          }
-        }
+        %{context: %{current_user: user}}
       ) do
     with %Actor{id: actor_id} <- Actors.get_local_actor_by_name(username),
          {:user_actor, true} <-
diff --git a/lib/mobilizon_web/router.ex b/lib/mobilizon_web/router.ex
index 363976b3e..2b92afe32 100644
--- a/lib/mobilizon_web/router.ex
+++ b/lib/mobilizon_web/router.ex
@@ -14,13 +14,13 @@ defmodule MobilizonWeb.Router do
   end
 
   pipeline :activity_pub_signature do
-    plug(MobilizonWeb.HTTPSignaturePlug)
-    plug(MobilizonWeb.Plugs.MappedSignatureToIdentity)
+    plug(Mobilizon.Federation.Plugs.HTTPSignatures)
+    plug(Mobilizon.Federation.Plugs.MappedSignatureToIdentity)
   end
 
   pipeline :relay do
-    plug(MobilizonWeb.HTTPSignaturePlug)
-    plug(MobilizonWeb.Plugs.MappedSignatureToIdentity)
+    plug(Mobilizon.Federation.Plugs.HTTPSignatures)
+    plug(Mobilizon.Federation.Plugs.MappedSignatureToIdentity)
     plug(:accepts, ["activity-json", "json"])
   end
 
diff --git a/lib/service/admin/action_log_service.ex b/lib/service/admin/action_log.ex
similarity index 91%
rename from lib/service/admin/action_log_service.ex
rename to lib/service/admin/action_log.ex
index 7acbdb3a7..ebafaad8d 100644
--- a/lib/service/admin/action_log_service.ex
+++ b/lib/service/admin/action_log.ex
@@ -1,12 +1,11 @@
-defmodule Mobilizon.Service.Admin.ActionLogService do
+defmodule Mobilizon.Service.Admin.ActionLog do
   @moduledoc """
   Module to handle action log creations.
   """
 
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Admin
+  alias Mobilizon.{Admin, Users}
   alias Mobilizon.Admin.ActionLog
-  alias Mobilizon.Users
   alias Mobilizon.Users.User
 
   @doc """
diff --git a/lib/service/events/tools.ex b/lib/service/events/tools.ex
deleted file mode 100644
index 6fd3934af..000000000
--- a/lib/service/events/tools.ex
+++ /dev/null
@@ -1,50 +0,0 @@
-defmodule Mobilizon.Service.Events.Tool do
-  @moduledoc """
-  Event-related tools
-  """
-  alias Mobilizon.Events
-  alias Mobilizon.Events.Event
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.Users.User
-  alias MobilizonWeb.Email
-  alias Mobilizon.Storage.Repo
-
-  @important_changes [:title, :begins_on, :ends_on, :status]
-
-  def calculate_event_diff_and_send_notifications(
-        %Event{} = old_event,
-        %Event{id: event_id} = event,
-        changes
-      ) do
-    important = MapSet.new(@important_changes)
-
-    diff =
-      changes
-      |> Map.keys()
-      |> MapSet.new()
-      |> MapSet.intersection(important)
-
-    if MapSet.size(diff) > 0 do
-      Repo.transaction(fn ->
-        event_id
-        |> Events.list_local_emails_user_participants_for_event_query()
-        |> Repo.stream()
-        |> Enum.to_list()
-        |> Enum.each(
-          &send_notification_for_event_update_to_participant(&1, old_event, event, diff)
-        )
-      end)
-    end
-  end
-
-  defp send_notification_for_event_update_to_participant(
-         {%Actor{} = actor, %User{locale: locale} = user},
-         %Event{} = old_event,
-         %Event{} = event,
-         diff
-       ) do
-    user
-    |> Email.Event.event_updated(actor, old_event, event, diff, locale)
-    |> Email.Mailer.deliver_later()
-  end
-end
diff --git a/lib/service/statistics.ex b/lib/service/statistics/statistics.ex
similarity index 93%
rename from lib/service/statistics.ex
rename to lib/service/statistics/statistics.ex
index 9d1f07ee8..349045dd1 100644
--- a/lib/service/statistics.ex
+++ b/lib/service/statistics/statistics.ex
@@ -2,8 +2,8 @@ defmodule Mobilizon.Service.Statistics do
   @moduledoc """
   A module that provides cached statistics
   """
-  alias Mobilizon.Events
-  alias Mobilizon.Users
+
+  alias Mobilizon.{Events, Users}
 
   def get_cached_value(key) do
     case Cachex.fetch(:statistics, key, fn key ->
diff --git a/lib/service/users/activation.ex b/lib/service/users/activation.ex
deleted file mode 100644
index 016650ce6..000000000
--- a/lib/service/users/activation.ex
+++ /dev/null
@@ -1,46 +0,0 @@
-defmodule Mobilizon.Service.Users.Activation do
-  @moduledoc false
-
-  alias Mobilizon.Service.Users.Tools
-  alias Mobilizon.Users
-  alias Mobilizon.Users.User
-
-  alias MobilizonWeb.Email
-
-  require Logger
-
-  @doc false
-  def check_confirmation_token(token) when is_binary(token) do
-    with %User{} = user <- Users.get_user_by_activation_token(token),
-         {:ok, %User{} = user} <-
-           Users.update_user(user, %{
-             "confirmed_at" => DateTime.utc_now() |> DateTime.truncate(:second),
-             "confirmation_sent_at" => nil,
-             "confirmation_token" => nil
-           }) do
-      Logger.info("User #{user.email} has been confirmed")
-      {:ok, user}
-    else
-      _err ->
-        {:error, :invalid_token}
-    end
-  end
-
-  def resend_confirmation_email(%User{} = user, locale \\ "en") do
-    with :ok <- Tools.we_can_send_email(user, :confirmation_sent_at),
-         {:ok, user} <-
-           Users.update_user(user, %{
-             "confirmation_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
-           }) do
-      send_confirmation_email(user, locale)
-      Logger.info("Sent confirmation email again to #{user.email}")
-      {:ok, user.email}
-    end
-  end
-
-  def send_confirmation_email(%User{} = user, locale \\ "en") do
-    user
-    |> Email.User.confirmation_email(locale)
-    |> Email.Mailer.deliver_later()
-  end
-end
diff --git a/lib/service/users/reset_password.ex b/lib/service/users/reset_password.ex
deleted file mode 100644
index 1fa744f54..000000000
--- a/lib/service/users/reset_password.ex
+++ /dev/null
@@ -1,62 +0,0 @@
-defmodule Mobilizon.Service.Users.ResetPassword do
-  @moduledoc false
-
-  alias Mobilizon.Service.Users.Tools
-  alias Mobilizon.Storage.Repo
-  alias Mobilizon.Users
-  alias Mobilizon.Users.User
-
-  alias MobilizonWeb.Email
-
-  require Logger
-
-  @doc """
-  Check that the provided token is correct and update provided password
-  """
-  @spec check_reset_password_token(String.t(), String.t()) :: tuple
-  def check_reset_password_token(password, token) do
-    with %User{} = user <- Users.get_user_by_reset_password_token(token),
-         {:ok, %User{} = user} <-
-           Repo.update(
-             User.password_reset_changeset(user, %{
-               "password" => password,
-               "reset_password_sent_at" => nil,
-               "reset_password_token" => nil
-             })
-           ) do
-      {:ok, user}
-    else
-      {:error, %Ecto.Changeset{errors: [password: {"registration.error.password_too_short", _}]}} ->
-        {:error,
-         "The password you have choosen is too short. Please make sure your password contains at least 6 charaters."}
-
-      _err ->
-        {:error,
-         "The token you provided is invalid. Make sure that the URL is exactly the one provided inside the email you got."}
-    end
-  end
-
-  @doc """
-  Send the email reset password, if it's not too soon since the last send
-  """
-  @spec send_password_reset_email(User.t(), String.t()) :: tuple
-  def send_password_reset_email(%User{} = user, locale \\ "en") do
-    with :ok <- Tools.we_can_send_email(user, :reset_password_sent_at),
-         {:ok, %User{} = user_updated} <-
-           Repo.update(
-             User.send_password_reset_changeset(user, %{
-               "reset_password_token" => Tools.random_string(30),
-               "reset_password_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
-             })
-           ) do
-      mail =
-        user_updated
-        |> Email.User.reset_password_email(locale)
-        |> Email.Mailer.deliver_later()
-
-      {:ok, mail}
-    else
-      {:error, reason} -> {:error, reason}
-    end
-  end
-end
diff --git a/lib/service/users/tools.ex b/lib/service/users/tools.ex
deleted file mode 100644
index 1dbf5d33a..000000000
--- a/lib/service/users/tools.ex
+++ /dev/null
@@ -1,43 +0,0 @@
-defmodule Mobilizon.Service.Users.Tools do
-  @moduledoc """
-  Common functions for actors services
-  """
-  alias Mobilizon.Users.User
-
-  @spec we_can_send_email(User.t(), atom()) :: :ok | {:error, :email_too_soon}
-  def we_can_send_email(%User{} = user, key \\ :reset_password_sent_at) do
-    case Map.get(user, key) do
-      nil ->
-        :ok
-
-      _ ->
-        case Timex.before?(
-               Timex.shift(Map.get(user, key), hours: 1),
-               DateTime.utc_now() |> DateTime.truncate(:second)
-             ) do
-          true ->
-            :ok
-
-          false ->
-            {:error, :email_too_soon}
-        end
-    end
-  end
-
-  @spec random_string(integer) :: String.t()
-  def random_string(length) do
-    length
-    |> :crypto.strong_rand_bytes()
-    |> Base.url_encode64()
-  end
-end
-
-defmodule Mobilizon.Users.Guards do
-  @moduledoc """
-  Guards for users
-  """
-
-  defguard is_admin(role) when is_atom(role) and role == :administrator
-
-  defguard is_moderator(role) when is_atom(role) and role in [:administrator, :moderator]
-end
diff --git a/lib/service/workers/background_worker.ex b/lib/service/workers/background.ex
similarity index 72%
rename from lib/service/workers/background_worker.ex
rename to lib/service/workers/background.ex
index 60cbe2122..816ee09b5 100644
--- a/lib/service/workers/background_worker.ex
+++ b/lib/service/workers/background.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.Workers.BackgroundWorker do
+defmodule Mobilizon.Service.Workers.Background do
   @moduledoc """
   Worker to build search results
   """
@@ -6,7 +6,7 @@ defmodule Mobilizon.Service.Workers.BackgroundWorker do
   alias Mobilizon.Actors
   alias Mobilizon.Actors.Actor
 
-  use Mobilizon.Service.Workers.WorkerHelper, queue: "background"
+  use Mobilizon.Service.Workers.Helper, queue: "background"
 
   @impl Oban.Worker
   def perform(%{"op" => "delete_actor", "actor_id" => actor_id}, _job) do
diff --git a/lib/service/workers/build_search_worker.ex b/lib/service/workers/build_search.ex
similarity index 92%
rename from lib/service/workers/build_search_worker.ex
rename to lib/service/workers/build_search.ex
index acf742056..21a4bce8d 100644
--- a/lib/service/workers/build_search_worker.ex
+++ b/lib/service/workers/build_search.ex
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.Workers.BuildSearchWorker do
+defmodule Mobilizon.Service.Workers.BuildSearch do
   @moduledoc """
   Worker to build search results
   """
@@ -8,7 +8,7 @@ defmodule Mobilizon.Service.Workers.BuildSearchWorker do
   alias Mobilizon.Storage.Repo
   alias Ecto.Adapters.SQL
 
-  use Mobilizon.Service.Workers.WorkerHelper, queue: "search"
+  use Mobilizon.Service.Workers.Helper, queue: "search"
 
   @impl Oban.Worker
   def perform(%{"op" => "insert_search_event", "event_id" => event_id}, _job) do
diff --git a/lib/service/workers/worker_helper.ex b/lib/service/workers/helper.ex
similarity index 85%
rename from lib/service/workers/worker_helper.ex
rename to lib/service/workers/helper.ex
index ed9bb47eb..6f07ac0cc 100644
--- a/lib/service/workers/worker_helper.ex
+++ b/lib/service/workers/helper.ex
@@ -3,12 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/workers/worker_helper.ex
 
-defmodule Mobilizon.Service.Workers.WorkerHelper do
+defmodule Mobilizon.Service.Workers.Helper do
   @moduledoc """
   Tools to ease dealing with workers
   """
+
   alias Mobilizon.Config
-  alias Mobilizon.Service.Workers.WorkerHelper
+  alias Mobilizon.Storage.Repo
 
   def worker_args(queue) do
     case Config.get([:workers, :retries, queue]) do
@@ -39,11 +40,11 @@ defmodule Mobilizon.Service.Workers.WorkerHelper do
       def enqueue(operation, params, worker_args \\ []) do
         params = Map.merge(%{"op" => operation}, params)
         queue_atom = String.to_existing_atom(unquote(queue))
-        worker_args = worker_args ++ WorkerHelper.worker_args(queue_atom)
+        worker_args = worker_args ++ __MODULE__.worker_args(queue_atom)
 
         unquote(caller_module)
         |> apply(:new, [params, worker_args])
-        |> Mobilizon.Storage.Repo.insert()
+        |> Repo.insert()
       end
     end
   end
diff --git a/mix.exs b/mix.exs
index 6d92edd14..280cf590f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -283,10 +283,10 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Federation.HTTPSignatures.Signature,
         Mobilizon.Federation.WebFinger,
         Mobilizon.Federation.WebFinger.XmlBuilder,
+        Mobilizon.Federation.Plugs.HTTPSignatures,
         MobilizonWeb.ActivityPub.ActorView,
         MobilizonWeb.ActivityPub.ObjectView,
         MobilizonWeb.ActivityPubController,
-        MobilizonWeb.HTTPSignaturePlug,
         MobilizonWeb.WebFingerController,
         MobilizonWeb.NodeInfoController
       ],
diff --git a/test/mobilizon_web/plugs/federating_plug_test.exs b/test/federation/plugs/federating_plug_test.exs
similarity index 74%
rename from test/mobilizon_web/plugs/federating_plug_test.exs
rename to test/federation/plugs/federating_plug_test.exs
index 74aa72ae5..8eaac9f02 100644
--- a/test/mobilizon_web/plugs/federating_plug_test.exs
+++ b/test/federation/plugs/federating_plug_test.exs
@@ -3,15 +3,15 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule MobilizonWeb.Plug.FederatingTest do
+defmodule Mobilizon.Federation.Plug.FederatingTest do
   use MobilizonWeb.ConnCase
 
+  alias Mobilizon.Federation.Plugs.Federating
+
   test "returns and halt the conn when federating is disabled" do
     Mobilizon.Config.put([:instance, :federating], false)
 
-    conn =
-      build_conn()
-      |> MobilizonWeb.Plugs.Federating.call(%{})
+    conn = Federating.call(build_conn(), %{})
 
     assert conn.status == 404
     assert conn.halted
@@ -20,9 +20,7 @@ defmodule MobilizonWeb.Plug.FederatingTest do
   test "does nothing when federating is enabled" do
     Mobilizon.Config.put([:instance, :federating], true)
 
-    conn =
-      build_conn()
-      |> MobilizonWeb.Plugs.Federating.call(%{})
+    conn = Federating.call(build_conn(), %{})
 
     refute conn.status
     refute conn.halted
diff --git a/test/mobilizon_web/plugs/mapped_identity_to_signature_plug_test.exs b/test/federation/plugs/mapped_identity_to_signature_plug_test.exs
similarity index 96%
rename from test/mobilizon_web/plugs/mapped_identity_to_signature_plug_test.exs
rename to test/federation/plugs/mapped_identity_to_signature_plug_test.exs
index 9af71da9d..27ab2b6fd 100644
--- a/test/mobilizon_web/plugs/mapped_identity_to_signature_plug_test.exs
+++ b/test/federation/plugs/mapped_identity_to_signature_plug_test.exs
@@ -3,9 +3,10 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule MobilizonWeb.Plugs.MappedSignatureToIdentityPlugTest do
+defmodule Mobilizon.Federation.Plugs.MappedSignatureToIdentityTest do
   use MobilizonWeb.ConnCase
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
+
   alias MobilizonWeb.Plugs.MappedSignatureToIdentity
 
   defp set_signature(conn, key_id) do
diff --git a/test/federation/web_finger_test.exs b/test/federation/web_finger/web_finger_test.exs
similarity index 100%
rename from test/federation/web_finger_test.exs
rename to test/federation/web_finger/web_finger_test.exs
diff --git a/test/mobilizon/actors/actors_test.exs b/test/mobilizon/actors/actors_test.exs
index 07d0945bd..a6f1d5828 100644
--- a/test/mobilizon/actors/actors_test.exs
+++ b/test/mobilizon/actors/actors_test.exs
@@ -9,6 +9,7 @@ defmodule Mobilizon.ActorsTest do
   alias Mobilizon.Actors.{Actor, Bot, Follower, Member}
   alias Mobilizon.Events.{Event, Comment}
   alias Mobilizon.Media.File, as: FileModel
+  alias Mobilizon.Service.Workers
   alias Mobilizon.Storage.Page
 
   alias Mobilizon.Federation.ActivityPub
@@ -311,7 +312,7 @@ defmodule Mobilizon.ActorsTest do
       assert {:ok, %Oban.Job{}} = Actors.delete_actor(actor)
 
       assert_enqueued(
-        worker: Mobilizon.Service.Workers.BackgroundWorker,
+        worker: Workers.Background,
         args: %{"actor_id" => actor.id, "op" => "delete_actor"}
       )
 
diff --git a/test/mobilizon/events/events_test.exs b/test/mobilizon/events/events_test.exs
index 5ecac1ae0..6a34b4720 100644
--- a/test/mobilizon/events/events_test.exs
+++ b/test/mobilizon/events/events_test.exs
@@ -6,8 +6,8 @@ defmodule Mobilizon.EventsTest do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.{Comment, Event, Participant, Session, Tag, TagRelation, Track}
+  alias Mobilizon.Service.Workers
   alias Mobilizon.Storage.Page
-  alias Mobilizon.Service.Workers.BuildSearchWorker
 
   @event_valid_attrs %{
     begins_on: "2010-04-17 14:00:00Z",
@@ -23,7 +23,7 @@ defmodule Mobilizon.EventsTest do
     setup do
       actor = insert(:actor)
       event = insert(:event, organizer_actor: actor, visibility: :public)
-      BuildSearchWorker.insert_search_event(event)
+      Workers.BuildSearch.insert_search_event(event)
       {:ok, actor: actor, event: event}
     end
 
@@ -63,7 +63,7 @@ defmodule Mobilizon.EventsTest do
       assert title == hd(Events.build_events_for_search(event.title).elements).title
 
       %Event{} = event2 = insert(:event, title: "Special event")
-      BuildSearchWorker.insert_search_event(event2)
+      Workers.BuildSearch.insert_search_event(event2)
 
       assert event2.title ==
                Events.build_events_for_search("Special").elements |> hd() |> Map.get(:title)
@@ -76,7 +76,7 @@ defmodule Mobilizon.EventsTest do
       tag1 = insert(:tag, title: "coucou")
       tag2 = insert(:tag, title: "hola")
       %Event{} = event3 = insert(:event, title: "Nothing like it", tags: [tag1, tag2])
-      BuildSearchWorker.insert_search_event(event3)
+      Workers.BuildSearch.insert_search_event(event3)
 
       assert event3.title ==
                Events.build_events_for_search("hola").elements |> hd() |> Map.get(:title)
diff --git a/test/service/users/tools.exs b/test/mobilizon/users/guards_test.exs
similarity index 94%
rename from test/service/users/tools.exs
rename to test/mobilizon/users/guards_test.exs
index 6c160bf97..117b5f37f 100644
--- a/test/service/users/tools.exs
+++ b/test/mobilizon/users/guards_test.exs
@@ -1,4 +1,4 @@
-defmodule Mobilizon.Service.Users.ToolsTest do
+defmodule Mobilizon.Users.GuardsTest do
   use Mobilizon.DataCase
 
   import Mobilizon.Factory
diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_resolver_test.exs
index 512c59cd0..44ae7dce0 100644
--- a/test/mobilizon_web/resolvers/event_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/event_resolver_test.exs
@@ -2,11 +2,14 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
   use MobilizonWeb.ConnCase
   use Bamboo.Test
   use Oban.Testing, repo: Mobilizon.Storage.Repo
-  alias Mobilizon.Events
-  alias MobilizonWeb.{AbsintheHelpers, Email}
-  alias Mobilizon.Service.Workers.BuildSearchWorker
+
   import Mobilizon.Factory
 
+  alias Mobilizon.Events
+  alias Mobilizon.Service.Workers
+
+  alias MobilizonWeb.{AbsintheHelpers, Email}
+
   @event %{
     description: "some body",
     title: "some title",
@@ -155,7 +158,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
 
       assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event"
       {id, ""} = json_response(res, 200)["data"]["createEvent"]["id"] |> Integer.parse()
-      assert_enqueued(worker: BuildSearchWorker, args: %{event_id: id, op: :insert_search_event})
+      assert_enqueued(worker: Workers.BuildSearch, args: %{event_id: id, op: :insert_search_event})
     end
 
     test "create_event/3 creates an event and escapes title and description", %{
@@ -201,7 +204,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
                "<b>My description</b> <img src=\"http://placekitten.com/g/200/300\" />"
 
       {id, ""} = res["data"]["createEvent"]["id"] |> Integer.parse()
-      assert_enqueued(worker: BuildSearchWorker, args: %{event_id: id, op: :insert_search_event})
+      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
@@ -238,7 +241,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
       {event_id_int, ""} = Integer.parse(event_id)
 
       refute_enqueued(
-        worker: BuildSearchWorker,
+        worker: Workers.BuildSearch,
         args: %{event_id: event_id_int, op: :insert_search_event}
       )
 
@@ -371,7 +374,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
       {event_id_int, ""} = Integer.parse(event["id"])
 
       assert_enqueued(
-        worker: BuildSearchWorker,
+        worker: Workers.BuildSearch,
         args: %{event_id: event_id_int, op: :insert_search_event}
       )
     end
@@ -827,7 +830,7 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
       {event_id_int, ""} = Integer.parse(event_res["id"])
 
       assert_enqueued(
-        worker: BuildSearchWorker,
+        worker: Workers.BuildSearch,
         args: %{event_id: event_id_int, op: :update_search_event}
       )
 
diff --git a/test/mobilizon_web/resolvers/person_resolver_test.exs b/test/mobilizon_web/resolvers/person_resolver_test.exs
index e0e7ae609..f2af5cc02 100644
--- a/test/mobilizon_web/resolvers/person_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/person_resolver_test.exs
@@ -1,10 +1,14 @@
 defmodule MobilizonWeb.Resolvers.PersonResolverTest do
   use MobilizonWeb.ConnCase
-  alias MobilizonWeb.AbsintheHelpers
-  alias Mobilizon.Actors.Actor
-  import Mobilizon.Factory
   use Oban.Testing, repo: Mobilizon.Storage.Repo
 
+  import Mobilizon.Factory
+
+  alias Mobilizon.Actors.Actor
+  alias Mobilizon.Service.Workers
+
+  alias MobilizonWeb.AbsintheHelpers
+
   @non_existent_username "nonexistent"
 
   describe "Person Resolver" do
@@ -500,7 +504,7 @@ defmodule MobilizonWeb.Resolvers.PersonResolverTest do
       assert json_response(res, 200)["errors"] == nil
 
       assert_enqueued(
-        worker: Mobilizon.Service.Workers.BackgroundWorker,
+        worker: Workers.Background,
         args: %{"actor_id" => person_id, "op" => "delete_actor"}
       )
 
diff --git a/test/mobilizon_web/resolvers/search_resolver_test.exs b/test/mobilizon_web/resolvers/search_resolver_test.exs
index a5c058e7f..9e3d89b05 100644
--- a/test/mobilizon_web/resolvers/search_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/search_resolver_test.exs
@@ -1,8 +1,10 @@
 defmodule MobilizonWeb.Resolvers.SearchResolverTest do
   use MobilizonWeb.ConnCase
-  alias MobilizonWeb.AbsintheHelpers
+
   import Mobilizon.Factory
-  alias Mobilizon.Service.Workers.BuildSearchWorker
+
+  alias Mobilizon.Service.Workers
+  alias MobilizonWeb.AbsintheHelpers
 
   setup %{conn: conn} do
     user = insert(:user)
@@ -17,7 +19,7 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     insert(:actor, user: user, preferred_username: "test_person")
     insert(:actor, type: :Group, preferred_username: "test_group")
     event = insert(:event, title: "test_event")
-    BuildSearchWorker.insert_search_event(event)
+    Workers.BuildSearch.insert_search_event(event)
 
     query = """
     {
@@ -51,7 +53,7 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     actor = insert(:actor, user: user, preferred_username: "test_person")
     insert(:actor, type: :Group, preferred_username: "test_group")
     event = insert(:event, title: "test_event")
-    BuildSearchWorker.insert_search_event(event)
+    Workers.BuildSearch.insert_search_event(event)
 
     query = """
     {
@@ -84,7 +86,7 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     insert(:actor, user: user, preferred_username: "test_person")
     group = insert(:actor, type: :Group, preferred_username: "test_group")
     event = insert(:event, title: "test_event")
-    BuildSearchWorker.insert_search_event(event)
+    Workers.BuildSearch.insert_search_event(event)
 
     query = """
     {
@@ -118,9 +120,9 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     event1 = insert(:event, title: "Pineapple fashion week")
     event2 = insert(:event, title: "I love pineAPPLE")
     event3 = insert(:event, title: "Hello")
-    BuildSearchWorker.insert_search_event(event1)
-    BuildSearchWorker.insert_search_event(event2)
-    BuildSearchWorker.insert_search_event(event3)
+    Workers.BuildSearch.insert_search_event(event1)
+    Workers.BuildSearch.insert_search_event(event2)
+    Workers.BuildSearch.insert_search_event(event3)
 
     query = """
     {
@@ -161,9 +163,9 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     event1 = insert(:event, title: "Pineapple fashion week")
     event2 = insert(:event, title: "I love pineAPPLE")
     event3 = insert(:event, title: "Hello")
-    BuildSearchWorker.insert_search_event(event1)
-    BuildSearchWorker.insert_search_event(event2)
-    BuildSearchWorker.insert_search_event(event3)
+    Workers.BuildSearch.insert_search_event(event1)
+    Workers.BuildSearch.insert_search_event(event2)
+    Workers.BuildSearch.insert_search_event(event3)
 
     query = """
     {
@@ -198,7 +200,7 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     insert(:actor, user: user, preferred_username: "person", name: "Torréfaction du Kafé")
     insert(:actor, type: :Group, preferred_username: "group", name: "Kafé group")
     event = insert(:event, title: "Tour du monde des Kafés")
-    BuildSearchWorker.insert_search_event(event)
+    Workers.BuildSearch.insert_search_event(event)
 
     # Elaborate query
     query = """
@@ -230,7 +232,7 @@ defmodule MobilizonWeb.Resolvers.SearchResolverTest do
     insert(:actor, user: user, preferred_username: "person", name: "Torréfaction du Kafé")
     group = insert(:actor, type: :Group, preferred_username: "group", name: "Kafé group")
     event = insert(:event, title: "Tour du monde des Kafés")
-    BuildSearchWorker.insert_search_event(event)
+    Workers.BuildSearch.insert_search_event(event)
 
     # Elaborate query
     query = """
diff --git a/test/service/admin/action_log_service_test.exs b/test/service/admin/action_log_test.exs
similarity index 89%
rename from test/service/admin/action_log_service_test.exs
rename to test/service/admin/action_log_test.exs
index 8ec336d37..5b6d61e07 100644
--- a/test/service/admin/action_log_service_test.exs
+++ b/test/service/admin/action_log_test.exs
@@ -1,12 +1,12 @@
-defmodule Mobilizon.Service.Admin.ActionLogServiceTest do
+defmodule Mobilizon.Service.Admin.ActionLogTest do
   @moduledoc """
-  Test the ActionLogService module.
+  Test the ActionLog module.
   """
 
   use Mobilizon.DataCase
 
   import Mobilizon.Factory
-  import Mobilizon.Service.Admin.ActionLogService
+  import Mobilizon.Service.Admin.ActionLog
 
   alias Mobilizon.Admin.ActionLog
   alias Mobilizon.Reports.{Note, Report}

From 3577fe42e1aeece974eedfc4dd7bc31fd30b25fc Mon Sep 17 00:00:00 2001
From: rustra <rustra@riseup.net>
Date: Thu, 23 Jan 2020 21:59:50 +0100
Subject: [PATCH 4/4] Improve Federation boundaries

---
 config/config.exs                             |   6 +-
 config/dev.exs                                |   4 +-
 config/test.exs                               |   6 +-
 lib/federation/activity_pub/transmogrifier.ex |   5 +-
 .../{ => converter}/converter.ex              |   0
 lib/mobilizon/admin/action_log.ex             |   8 -
 lib/mobilizon/admin/admin.ex                  |  39 +++++
 lib/mobilizon/events/events.ex                |   7 +-
 lib/mobilizon/users/users.ex                  |   6 +-
 lib/mobilizon_web/api/reports.ex              |  10 +-
 lib/mobilizon_web/{ => auth}/context.ex       |   6 +-
 .../error_handler.ex}                         |   2 +-
 lib/mobilizon_web/{ => auth}/guardian.ex      |   4 +-
 .../{auth_pipeline.ex => auth/pipeline.ex}    |   8 +-
 lib/mobilizon_web/cache/activity_pub.ex       |   4 +-
 lib/mobilizon_web/{ => cache}/cache.ex        |   0
 lib/mobilizon_web/channels/graphql_socket.ex  |   2 +-
 .../controllers/activity_pub_controller.ex    |   6 +-
 .../controllers/web_finger_controller.ex      |   2 +-
 lib/mobilizon_web/email/user.ex               |   6 +-
 .../plugs/federating.ex                       |   2 +-
 .../plugs/http_signatures.ex}                 |   2 +-
 .../plugs/mapped_signature_to_identity.ex     |   0
 lib/mobilizon_web/{ => proxy}/media_proxy.ex  |   0
 .../{ => proxy}/reverse_proxy.ex              |   0
 lib/mobilizon_web/resolvers/comment.ex        |   6 +-
 lib/mobilizon_web/resolvers/event.ex          |   7 +-
 lib/mobilizon_web/resolvers/user.ex           |   6 +-
 lib/mobilizon_web/router.ex                   |  62 ++++----
 .../schema/custom/{UUID4.ex => uuid4.ex}      |   0
 .../upload/{ => filter}/filter.ex             |   0
 lib/mobilizon_web/{ => upload}/mime.ex        |   2 +-
 lib/mobilizon_web/{ => upload}/upload.ex      |  10 +-
 .../{uploaders => upload/uploader}/local.ex   |   4 +-
 .../uploader}/uploader.ex                     |   2 +-
 .../views/activity_pub}/actor_view.ex         |   0
 .../views/activity_pub}/object_view.ex        |   0
 lib/service/admin/action_log.ex               |  39 -----
 lib/service/formatter/html.ex                 |   1 -
 lib/service/workers/helper.ex                 |   3 +-
 mix.exs                                       | 141 ++++++++++++++----
 test/mobilizon/actors/actors_test.exs         |  18 ++-
 .../admin/action_log_test.exs                 |   6 +-
 test/mobilizon/media/media_test.exs           |   6 +-
 .../plugs/federating_test.exs}                |   4 +-
 .../mapped_identity_to_signature_test.exs}    |   2 +-
 ..._plug_test.exs => uploaded_media_test.exs} |   0
 .../{ => proxy}/media_proxy_test.exs          |   0
 ...ess_resolver_test.exs => address_test.exs} |   0
 ...admin_resolver_test.exs => admin_test.exs} |   0
 ...ent_resolver_test.exs => comment_test.exs} |   0
 ...nfig_resolver_test.exs => config_test.exs} |   0
 ...event_resolver_test.exs => event_test.exs} |  12 +-
 ..._resolver_test.exs => feed_token_test.exs} |   0
 ...group_resolver_test.exs => group_test.exs} |   0
 ...mber_resolver_test.exs => member_test.exs} |   0
 ...resolver_test.exs => participant_test.exs} |   0
 ...rson_resolver_test.exs => person_test.exs} |   0
 ...ure_resolver_test.exs => picture_test.exs} |   0
 ...port_resolver_test.exs => report_test.exs} |   0
 ...arch_resolver_test.exs => search_test.exs} |   0
 .../{tag_resolver_test.exs => tag_test.exs}   |   0
 .../{user_resolver_test.exs => user_test.exs} |  48 +++---
 .../{ => upload}/upload_test.exs              |   5 +-
 test/support/conn_case.ex                     |   2 +-
 test/support/data_case.ex                     |  17 ++-
 test/tasks/users_test.exs                     |   3 +-
 67 files changed, 314 insertions(+), 227 deletions(-)
 rename lib/federation/activity_stream/{ => converter}/converter.ex (100%)
 rename lib/mobilizon_web/{ => auth}/context.ex (82%)
 rename lib/mobilizon_web/{auth_error_handler.ex => auth/error_handler.ex} (83%)
 rename lib/mobilizon_web/{ => auth}/guardian.ex (97%)
 rename lib/mobilizon_web/{auth_pipeline.ex => auth/pipeline.ex} (56%)
 rename lib/mobilizon_web/{ => cache}/cache.ex (100%)
 rename lib/{federation => mobilizon_web}/controllers/activity_pub_controller.ex (95%)
 rename lib/{federation => mobilizon_web}/plugs/federating.ex (92%)
 rename lib/{federation/plugs/http_signature.ex => mobilizon_web/plugs/http_signatures.ex} (96%)
 rename lib/{federation => mobilizon_web}/plugs/mapped_signature_to_identity.ex (100%)
 rename lib/mobilizon_web/{ => proxy}/media_proxy.ex (100%)
 rename lib/mobilizon_web/{ => proxy}/reverse_proxy.ex (100%)
 rename lib/mobilizon_web/schema/custom/{UUID4.ex => uuid4.ex} (100%)
 rename lib/mobilizon_web/upload/{ => filter}/filter.ex (100%)
 rename lib/mobilizon_web/{ => upload}/mime.ex (98%)
 rename lib/mobilizon_web/{ => upload}/upload.ex (95%)
 rename lib/mobilizon_web/{uploaders => upload/uploader}/local.ex (94%)
 rename lib/mobilizon_web/{uploaders => upload/uploader}/uploader.ex (98%)
 rename lib/{federation/views => mobilizon_web/views/activity_pub}/actor_view.ex (100%)
 rename lib/{federation/views => mobilizon_web/views/activity_pub}/object_view.ex (100%)
 delete mode 100644 lib/service/admin/action_log.ex
 rename test/{service => mobilizon}/admin/action_log_test.exs (88%)
 rename test/{federation/plugs/federating_plug_test.exs => mobilizon_web/plugs/federating_test.exs} (87%)
 rename test/{federation/plugs/mapped_identity_to_signature_plug_test.exs => mobilizon_web/plugs/mapped_identity_to_signature_test.exs} (96%)
 rename test/mobilizon_web/plugs/{uploaded_media_plug_test.exs => uploaded_media_test.exs} (100%)
 rename test/mobilizon_web/{ => proxy}/media_proxy_test.exs (100%)
 rename test/mobilizon_web/resolvers/{address_resolver_test.exs => address_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{admin_resolver_test.exs => admin_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{comment_resolver_test.exs => comment_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{config_resolver_test.exs => config_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{event_resolver_test.exs => event_test.exs} (99%)
 rename test/mobilizon_web/resolvers/{feed_token_resolver_test.exs => feed_token_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{group_resolver_test.exs => group_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{member_resolver_test.exs => member_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{participant_resolver_test.exs => participant_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{person_resolver_test.exs => person_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{picture_resolver_test.exs => picture_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{report_resolver_test.exs => report_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{search_resolver_test.exs => search_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{tag_resolver_test.exs => tag_test.exs} (100%)
 rename test/mobilizon_web/resolvers/{user_resolver_test.exs => user_test.exs} (95%)
 rename test/mobilizon_web/{ => upload}/upload_test.exs (97%)

diff --git a/config/config.exs b/config/config.exs
index d4996a4bb..64e0bdc0d 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -44,7 +44,7 @@ config :mobilizon, MobilizonWeb.Endpoint,
 
 # Upload configuration
 config :mobilizon, MobilizonWeb.Upload,
-  uploader: MobilizonWeb.Uploaders.Local,
+  uploader: MobilizonWeb.Upload.Uploader.Local,
   filters: [
     MobilizonWeb.Upload.Filter.Dedupe,
     MobilizonWeb.Upload.Filter.Optimize
@@ -60,7 +60,7 @@ config :mobilizon, MobilizonWeb.Upload,
     ]
   ]
 
-config :mobilizon, MobilizonWeb.Uploaders.Local, uploads: "uploads"
+config :mobilizon, MobilizonWeb.Upload.Uploader.Local, uploads: "uploads"
 
 config :mobilizon, :media_proxy,
   enabled: true,
@@ -78,7 +78,7 @@ config :logger, :console,
   format: "$time $metadata[$level] $message\n",
   metadata: [:request_id]
 
-config :mobilizon, MobilizonWeb.Guardian,
+config :mobilizon, MobilizonWeb.Auth.Guardian,
   issuer: "mobilizon",
   secret_key: "ty0WM7YBE3ojvxoUQxo8AERrNpfbXnIJ82ovkPdqbUFw31T5LcK8wGjaOiReVQjo"
 
diff --git a/config/dev.exs b/config/dev.exs
index 0ffb389f8..ac5f5a921 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -66,8 +66,8 @@ config :mobilizon, MobilizonWeb.Email.Mailer, adapter: Bamboo.LocalAdapter
 # Configure your database
 config :mobilizon, Mobilizon.Storage.Repo,
   types: Mobilizon.Storage.PostgresTypes,
-  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "postgres",
-  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "postgres",
+  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "mobilizon",
+  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "mobilizon",
   database: System.get_env("MOBILIZON_DATABASE_DBNAME") || "mobilizon_dev",
   hostname: System.get_env("MOBILIZON_DATABASE_HOST") || "localhost",
   port: System.get_env("MOBILIZON_DATABASE_PORT") || "5432",
diff --git a/config/test.exs b/config/test.exs
index 15a3fcb77..7a43f0ed3 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -24,8 +24,8 @@ config :logger,
 # Configure your database
 config :mobilizon, Mobilizon.Storage.Repo,
   types: Mobilizon.Storage.PostgresTypes,
-  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "postgres",
-  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "postgres",
+  username: System.get_env("MOBILIZON_DATABASE_USERNAME") || "mobilizon",
+  password: System.get_env("MOBILIZON_DATABASE_PASSWORD") || "mobilizon",
   database: System.get_env("MOBILIZON_DATABASE_DBNAME") || "mobilizon_test",
   hostname: System.get_env("MOBILIZON_DATABASE_HOST") || "localhost",
   pool: Ecto.Adapters.SQL.Sandbox
@@ -34,7 +34,7 @@ config :mobilizon, MobilizonWeb.Email.Mailer, adapter: Bamboo.TestAdapter
 
 config :mobilizon, MobilizonWeb.Upload, filters: [], link_name: false
 
-config :mobilizon, MobilizonWeb.Uploaders.Local, uploads: "test/uploads"
+config :mobilizon, MobilizonWeb.Upload.Uploader.Local, uploads: "test/uploads"
 
 config :exvcr,
   vcr_cassette_library_dir: "test/fixtures/vcr_cassettes"
diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex
index 481fbe88e..21ae9c2db 100644
--- a/lib/federation/activity_pub/transmogrifier.ex
+++ b/lib/federation/activity_pub/transmogrifier.ex
@@ -221,7 +221,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
         %{"type" => "Update", "object" => %{"type" => "Event"} = object, "actor" => _actor} =
           update_data
       ) do
-        with actor <- Utils.get_actor(update_data),
+    with actor <- Utils.get_actor(update_data),
          {:ok, %Actor{url: actor_url}} <- Actors.get_actor_by_url(actor),
          {:ok, %Event{} = old_event} <-
            object |> Utils.get_url() |> ActivityPub.fetch_object_from_url(),
@@ -289,7 +289,8 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
     with actor <- Utils.get_actor(data),
          {:ok, %Actor{url: actor_url}} <- Actors.get_actor_by_url(actor),
          object_id <- Utils.get_url(object),
-         {:origin_check, true} <- {:origin_check, Utils.origin_check_from_id?(actor_url, object_id)},
+         {:origin_check, true} <-
+           {:origin_check, Utils.origin_check_from_id?(actor_url, object_id)},
          {:ok, object} <- ActivityPub.fetch_object_from_url(object_id),
          {:ok, activity, object} <- ActivityPub.delete(object, false) do
       {:ok, activity, object}
diff --git a/lib/federation/activity_stream/converter.ex b/lib/federation/activity_stream/converter/converter.ex
similarity index 100%
rename from lib/federation/activity_stream/converter.ex
rename to lib/federation/activity_stream/converter/converter.ex
diff --git a/lib/mobilizon/admin/action_log.ex b/lib/mobilizon/admin/action_log.ex
index 49e823043..9aa98000d 100644
--- a/lib/mobilizon/admin/action_log.ex
+++ b/lib/mobilizon/admin/action_log.ex
@@ -1,11 +1,3 @@
-import EctoEnum
-
-defenum(Mobilizon.Admin.ActionLogAction, [
-  "update",
-  "create",
-  "delete"
-])
-
 defmodule Mobilizon.Admin.ActionLog do
   @moduledoc """
   Represents an action log entity.
diff --git a/lib/mobilizon/admin/admin.ex b/lib/mobilizon/admin/admin.ex
index 3d162434f..4c76ae217 100644
--- a/lib/mobilizon/admin/admin.ex
+++ b/lib/mobilizon/admin/admin.ex
@@ -4,9 +4,19 @@ defmodule Mobilizon.Admin do
   """
 
   import Ecto.Query
+  import EctoEnum
 
+  alias Mobilizon.Actors.Actor
+  alias Mobilizon.{Admin, Users}
   alias Mobilizon.Admin.ActionLog
   alias Mobilizon.Storage.{Page, Repo}
+  alias Mobilizon.Users.User
+
+  defenum(ActionLogAction, [
+    "update",
+    "create",
+    "delete"
+  ])
 
   @doc """
   Creates a action_log.
@@ -28,8 +38,37 @@ defmodule Mobilizon.Admin do
     |> Repo.all()
   end
 
+  @doc """
+  Log an admin action
+  """
+  @spec log_action(Actor.t(), String.t(), String.t()) :: {:ok, ActionLog.t()}
+  def log_action(%Actor{user_id: user_id, id: actor_id}, action, target) do
+    with %User{role: role} <- Users.get_user!(user_id),
+         {:role, true} <- {:role, role in [:administrator, :moderator]},
+         {:ok, %ActionLog{} = create_action_log} <-
+           Admin.create_action_log(%{
+             "actor_id" => actor_id,
+             "target_type" => to_string(target.__struct__),
+             "target_id" => target.id,
+             "action" => action,
+             "changes" => stringify_struct(target)
+           }) do
+      {:ok, create_action_log}
+    end
+  end
+
   @spec list_action_logs_query :: Ecto.Query.t()
   defp list_action_logs_query do
     from(r in ActionLog, preload: [:actor], order_by: [desc: :id])
   end
+
+  defp stringify_struct(%_{} = struct) do
+    association_fields = struct.__struct__.__schema__(:associations)
+
+    struct
+    |> Map.from_struct()
+    |> Map.drop(association_fields ++ [:__meta__])
+  end
+
+  defp stringify_struct(struct), do: struct
 end
diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 94bcfef9b..0c277892b 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -7,10 +7,11 @@ defmodule Mobilizon.Events do
 
   import Ecto.Query
   import EctoEnum
-  alias Ecto.{Multi, Changeset}
 
   import Mobilizon.Storage.Ecto
 
+  alias Ecto.{Multi, Changeset}
+
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Addresses.Address
 
@@ -331,14 +332,14 @@ defmodule Mobilizon.Events do
            |> Repo.transaction() do
       Cachex.del(:ics, "event_#{new_event.uuid}")
 
-      Email.Events.calculate_event_diff_and_send_notifications(
+      Email.Event.calculate_event_diff_and_send_notifications(
         old_event,
         new_event,
         changes
       )
 
       unless new_event.draft,
-        do: BuildSearch.enqueue(:update_search_event, %{"event_id" => new_event.id})
+        do: Workers.BuildSearch.enqueue(:update_search_event, %{"event_id" => new_event.id})
 
       {:ok, Repo.preload(new_event, @event_preloads)}
     end
diff --git a/lib/mobilizon/users/users.ex b/lib/mobilizon/users/users.ex
index 802dc42b2..cb6c3e665 100644
--- a/lib/mobilizon/users/users.ex
+++ b/lib/mobilizon/users/users.ex
@@ -13,6 +13,8 @@ defmodule Mobilizon.Users do
   alias Mobilizon.Storage.{Page, Repo}
   alias Mobilizon.Users.User
 
+  alias MobilizonWeb.Auth
+
   @type tokens :: %{
           required(:access_token) => String.t(),
           required(:refresh_token) => String.t()
@@ -247,7 +249,7 @@ defmodule Mobilizon.Users do
   @spec generate_access_token(User.t()) :: {:ok, String.t()}
   def generate_access_token(user) do
     with {:ok, access_token, _claims} <-
-           MobilizonWeb.Guardian.encode_and_sign(user, %{}, token_type: "access") do
+           Auth.Guardian.encode_and_sign(user, %{}, token_type: "access") do
       {:ok, access_token}
     end
   end
@@ -258,7 +260,7 @@ defmodule Mobilizon.Users do
   @spec generate_refresh_token(User.t()) :: {:ok, String.t()}
   def generate_refresh_token(user) do
     with {:ok, refresh_token, _claims} <-
-           MobilizonWeb.Guardian.encode_and_sign(user, %{}, token_type: "refresh") do
+           Auth.Guardian.encode_and_sign(user, %{}, token_type: "refresh") do
       {:ok, refresh_token}
     end
   end
diff --git a/lib/mobilizon_web/api/reports.ex b/lib/mobilizon_web/api/reports.ex
index 582ae4312..2281f47e4 100644
--- a/lib/mobilizon_web/api/reports.ex
+++ b/lib/mobilizon_web/api/reports.ex
@@ -3,12 +3,10 @@ defmodule MobilizonWeb.API.Reports do
   API for Reports.
   """
 
-  import Mobilizon.Service.Admin.ActionLog
-
   alias Mobilizon.Actors.Actor
+  alias Mobilizon.{Admin, Users}
   alias Mobilizon.Reports, as: ReportsAction
   alias Mobilizon.Reports.{Note, Report, ReportStatus}
-  alias Mobilizon.Users
   alias Mobilizon.Users.User
 
   alias Mobilizon.Federation.ActivityPub
@@ -34,7 +32,7 @@ defmodule MobilizonWeb.API.Reports do
     with {:valid_state, true} <-
            {:valid_state, ReportStatus.valid_value?(state)},
          {:ok, report} <- ReportsAction.update_report(report, %{"status" => state}),
-         {:ok, _} <- log_action(actor, "update", report) do
+         {:ok, _} <- Admin.log_action(actor, "update", report) do
       {:ok, report}
     else
       {:valid_state, false} -> {:error, "Unsupported state"}
@@ -58,7 +56,7 @@ defmodule MobilizonWeb.API.Reports do
              "moderator_id" => moderator_id,
              "content" => content
            }),
-         {:ok, _} <- log_action(moderator, "create", note) do
+         {:ok, _} <- Admin.log_action(moderator, "create", note) do
       {:ok, note}
     else
       {:role, false} ->
@@ -79,7 +77,7 @@ defmodule MobilizonWeb.API.Reports do
          {:role, true} <- {:role, role in [:administrator, :moderator]},
          {:ok, %Note{} = note} <-
            Mobilizon.Reports.delete_note(note),
-         {:ok, _} <- log_action(moderator, "delete", note) do
+         {:ok, _} <- Admin.log_action(moderator, "delete", note) do
       {:ok, note}
     else
       {:role, false} ->
diff --git a/lib/mobilizon_web/context.ex b/lib/mobilizon_web/auth/context.ex
similarity index 82%
rename from lib/mobilizon_web/context.ex
rename to lib/mobilizon_web/auth/context.ex
index 7721162d4..f47ccfa6e 100644
--- a/lib/mobilizon_web/context.ex
+++ b/lib/mobilizon_web/auth/context.ex
@@ -1,10 +1,11 @@
-defmodule MobilizonWeb.Context do
+defmodule MobilizonWeb.Auth.Context do
   @moduledoc """
   Guardian context for MobilizonWeb
   """
   @behaviour Plug
 
   import Plug.Conn
+
   alias Mobilizon.Users.User
 
   def init(opts) do
@@ -17,8 +18,7 @@ defmodule MobilizonWeb.Context do
     context =
       case Guardian.Plug.current_resource(conn) do
         %User{} = user ->
-          context
-          |> Map.put(:current_user, user)
+          Map.put(context, :current_user, user)
 
         nil ->
           context
diff --git a/lib/mobilizon_web/auth_error_handler.ex b/lib/mobilizon_web/auth/error_handler.ex
similarity index 83%
rename from lib/mobilizon_web/auth_error_handler.ex
rename to lib/mobilizon_web/auth/error_handler.ex
index 853ff92be..ae7a02824 100644
--- a/lib/mobilizon_web/auth_error_handler.ex
+++ b/lib/mobilizon_web/auth/error_handler.ex
@@ -1,4 +1,4 @@
-defmodule MobilizonWeb.AuthErrorHandler do
+defmodule MobilizonWeb.Auth.ErrorHandler do
   @moduledoc """
   In case we have an auth error
   """
diff --git a/lib/mobilizon_web/guardian.ex b/lib/mobilizon_web/auth/guardian.ex
similarity index 97%
rename from lib/mobilizon_web/guardian.ex
rename to lib/mobilizon_web/auth/guardian.ex
index 8fd954c6d..225be5a85 100644
--- a/lib/mobilizon_web/guardian.ex
+++ b/lib/mobilizon_web/auth/guardian.ex
@@ -1,7 +1,8 @@
-defmodule MobilizonWeb.Guardian do
+defmodule MobilizonWeb.Auth.Guardian do
   @moduledoc """
   Handles the JWT tokens encoding and decoding
   """
+
   use Guardian,
     otp_app: :mobilizon,
     permissions: %{
@@ -11,6 +12,7 @@ defmodule MobilizonWeb.Guardian do
 
   alias Mobilizon.Users
   alias Mobilizon.Users.User
+
   require Logger
 
   def subject_for_token(%User{} = user, _claims) do
diff --git a/lib/mobilizon_web/auth_pipeline.ex b/lib/mobilizon_web/auth/pipeline.ex
similarity index 56%
rename from lib/mobilizon_web/auth_pipeline.ex
rename to lib/mobilizon_web/auth/pipeline.ex
index 1f2a753a0..e8bc59e69 100644
--- a/lib/mobilizon_web/auth_pipeline.ex
+++ b/lib/mobilizon_web/auth/pipeline.ex
@@ -1,14 +1,14 @@
-defmodule MobilizonWeb.AuthPipeline do
+defmodule MobilizonWeb.Auth.Pipeline do
   @moduledoc """
   Handles the app sessions
   """
 
   use Guardian.Plug.Pipeline,
     otp_app: :mobilizon,
-    module: MobilizonWeb.Guardian,
-    error_handler: MobilizonWeb.AuthErrorHandler
+    module: MobilizonWeb.Auth.Guardian,
+    error_handler: MobilizonWeb.Auth.ErrorHandler
 
   plug(Guardian.Plug.VerifyHeader, realm: "Bearer")
   plug(Guardian.Plug.LoadResource, allow_blank: true)
-  plug(MobilizonWeb.Context)
+  plug(MobilizonWeb.Auth.Context)
 end
diff --git a/lib/mobilizon_web/cache/activity_pub.ex b/lib/mobilizon_web/cache/activity_pub.ex
index d91c1cb17..c73933123 100644
--- a/lib/mobilizon_web/cache/activity_pub.ex
+++ b/lib/mobilizon_web/cache/activity_pub.ex
@@ -1,6 +1,6 @@
 defmodule MobilizonWeb.Cache.ActivityPub do
   @moduledoc """
-  The ActivityPub related functions.
+  ActivityPub related cache.
   """
 
   alias Mobilizon.{Actors, Events, Tombstone}
@@ -9,8 +9,8 @@ defmodule MobilizonWeb.Cache.ActivityPub do
 
   alias Mobilizon.Federation.ActivityPub.Relay
 
-  alias MobilizonWeb.Router.Helpers, as: Routes
   alias MobilizonWeb.Endpoint
+  alias MobilizonWeb.Router.Helpers, as: Routes
 
   @cache :activity_pub
 
diff --git a/lib/mobilizon_web/cache.ex b/lib/mobilizon_web/cache/cache.ex
similarity index 100%
rename from lib/mobilizon_web/cache.ex
rename to lib/mobilizon_web/cache/cache.ex
diff --git a/lib/mobilizon_web/channels/graphql_socket.ex b/lib/mobilizon_web/channels/graphql_socket.ex
index 72372a663..dc51892e2 100644
--- a/lib/mobilizon_web/channels/graphql_socket.ex
+++ b/lib/mobilizon_web/channels/graphql_socket.ex
@@ -8,7 +8,7 @@ defmodule MobilizonWeb.GraphQLSocket do
 
   def connect(%{"token" => token}, socket) do
     with {:ok, authed_socket} <-
-           Guardian.Phoenix.Socket.authenticate(socket, MobilizonWeb.Guardian, token),
+           Guardian.Phoenix.Socket.authenticate(socket, MobilizonWeb.Auth.Guardian, token),
          %User{} = user <- Guardian.Phoenix.Socket.current_resource(authed_socket) do
       authed_socket =
         Absinthe.Phoenix.Socket.put_options(socket,
diff --git a/lib/federation/controllers/activity_pub_controller.ex b/lib/mobilizon_web/controllers/activity_pub_controller.ex
similarity index 95%
rename from lib/federation/controllers/activity_pub_controller.ex
rename to lib/mobilizon_web/controllers/activity_pub_controller.ex
index 2893ab0d4..a7b2407af 100644
--- a/lib/federation/controllers/activity_pub_controller.ex
+++ b/lib/mobilizon_web/controllers/activity_pub_controller.ex
@@ -3,8 +3,8 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/web/activity_pub/activity_pub_controller.ex
 
-defmodule Mobilizon.Federation.ActivityPubController do
-  use Mobilizon.Federation, :controller
+defmodule MobilizonWeb.ActivityPubController do
+  use MobilizonWeb, :controller
 
   alias Mobilizon.{Actors, Config}
   alias Mobilizon.Actors.Actor
@@ -19,7 +19,7 @@ defmodule Mobilizon.Federation.ActivityPubController do
 
   action_fallback(:errors)
 
-  plug(Mobilizon.Federation.Plugs.Federating when action in [:inbox, :relay])
+  plug(MobilizonWeb.Plugs.Federating when action in [:inbox, :relay])
   plug(:relay_active? when action in [:relay])
 
   def relay_active?(conn, _) do
diff --git a/lib/mobilizon_web/controllers/web_finger_controller.ex b/lib/mobilizon_web/controllers/web_finger_controller.ex
index d831ede32..6e96dc487 100644
--- a/lib/mobilizon_web/controllers/web_finger_controller.ex
+++ b/lib/mobilizon_web/controllers/web_finger_controller.ex
@@ -12,7 +12,7 @@ defmodule MobilizonWeb.WebFingerController do
 
   alias Mobilizon.Federation.WebFinger
 
-  plug(Mobilizon.Federation.Plugs.Federating)
+  plug(MobilizonWeb.Plugs.Federating)
 
   @doc """
   Provides /.well-known/host-meta
diff --git a/lib/mobilizon_web/email/user.ex b/lib/mobilizon_web/email/user.ex
index 131cd4f5b..74af18740 100644
--- a/lib/mobilizon_web/email/user.ex
+++ b/lib/mobilizon_web/email/user.ex
@@ -149,9 +149,9 @@ defmodule MobilizonWeb.Email.User do
 
       _ ->
         case Timex.before?(
-              Timex.shift(Map.get(user, key), hours: 1),
-              DateTime.utc_now() |> DateTime.truncate(:second)
-            ) do
+               Timex.shift(Map.get(user, key), hours: 1),
+               DateTime.utc_now() |> DateTime.truncate(:second)
+             ) do
           true ->
             :ok
 
diff --git a/lib/federation/plugs/federating.ex b/lib/mobilizon_web/plugs/federating.ex
similarity index 92%
rename from lib/federation/plugs/federating.ex
rename to lib/mobilizon_web/plugs/federating.ex
index 8af7f8e91..07dcca734 100644
--- a/lib/federation/plugs/federating.ex
+++ b/lib/mobilizon_web/plugs/federating.ex
@@ -3,7 +3,7 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule Mobilizon.Federation.Plugs.Federating do
+defmodule MobilizonWeb.Plugs.Federating do
   @moduledoc """
   Restrict ActivityPub routes when not federating
   """
diff --git a/lib/federation/plugs/http_signature.ex b/lib/mobilizon_web/plugs/http_signatures.ex
similarity index 96%
rename from lib/federation/plugs/http_signature.ex
rename to lib/mobilizon_web/plugs/http_signatures.ex
index 1075eba54..1dc669544 100644
--- a/lib/federation/plugs/http_signature.ex
+++ b/lib/mobilizon_web/plugs/http_signatures.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/plugs/http_signature.ex
 
-defmodule Mobilizon.Federation.Plugs.HTTPSignatures do
+defmodule MobilizonWeb.Plugs.HTTPSignatures do
   @moduledoc """
   Plug to check HTTP Signatures on every incoming request
   """
diff --git a/lib/federation/plugs/mapped_signature_to_identity.ex b/lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
similarity index 100%
rename from lib/federation/plugs/mapped_signature_to_identity.ex
rename to lib/mobilizon_web/plugs/mapped_signature_to_identity.ex
diff --git a/lib/mobilizon_web/media_proxy.ex b/lib/mobilizon_web/proxy/media_proxy.ex
similarity index 100%
rename from lib/mobilizon_web/media_proxy.ex
rename to lib/mobilizon_web/proxy/media_proxy.ex
diff --git a/lib/mobilizon_web/reverse_proxy.ex b/lib/mobilizon_web/proxy/reverse_proxy.ex
similarity index 100%
rename from lib/mobilizon_web/reverse_proxy.ex
rename to lib/mobilizon_web/proxy/reverse_proxy.ex
diff --git a/lib/mobilizon_web/resolvers/comment.ex b/lib/mobilizon_web/resolvers/comment.ex
index 094f18d37..0810c3a9c 100644
--- a/lib/mobilizon_web/resolvers/comment.ex
+++ b/lib/mobilizon_web/resolvers/comment.ex
@@ -3,9 +3,7 @@ defmodule MobilizonWeb.Resolvers.Comment do
   Handles the comment-related GraphQL calls.
   """
 
-  import Mobilizon.Service.Admin.ActionLog
-
-  alias Mobilizon.Actors
+  alias Mobilizon.{Actors, Admin, Events}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Events
   alias Mobilizon.Events.Comment, as: CommentModel
@@ -49,7 +47,7 @@ defmodule MobilizonWeb.Resolvers.Comment do
         role in [:moderator, :administrator] ->
           with {:ok, res} <- do_delete_comment(comment),
                %Actor{} = actor <- Actors.get_actor(actor_id) do
-            log_action(actor, "delete", comment)
+            Admin.log_action(actor, "delete", comment)
 
             {:ok, res}
           end
diff --git a/lib/mobilizon_web/resolvers/event.ex b/lib/mobilizon_web/resolvers/event.ex
index 086cdc296..59a0100e8 100644
--- a/lib/mobilizon_web/resolvers/event.ex
+++ b/lib/mobilizon_web/resolvers/event.ex
@@ -3,11 +3,8 @@ defmodule MobilizonWeb.Resolvers.Event do
   Handles the event-related GraphQL calls.
   """
 
-  import Mobilizon.Service.Admin.ActionLog
-
-  alias Mobilizon.Actors
+  alias Mobilizon.{Actors, Admin, Events}
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Events
   alias Mobilizon.Events.{Event, Participant, EventParticipantStats}
   alias Mobilizon.Users.User
 
@@ -343,7 +340,7 @@ defmodule MobilizonWeb.Resolvers.Event do
         role in [:moderator, :administrator] ->
           with {:ok, res} <- do_delete_event(event, !is_local),
                %Actor{} = actor <- Actors.get_actor(actor_id) do
-            log_action(actor, "delete", event)
+            Admin.log_action(actor, "delete", event)
 
             {:ok, res}
           end
diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex
index 6d09f88db..c9ab7c2b4 100644
--- a/lib/mobilizon_web/resolvers/user.ex
+++ b/lib/mobilizon_web/resolvers/user.ex
@@ -10,7 +10,7 @@ defmodule MobilizonWeb.Resolvers.User do
   alias Mobilizon.Storage.Repo
   alias Mobilizon.Users.User
 
-  alias MobilizonWeb.Email
+  alias MobilizonWeb.{Auth, Email}
 
   require Logger
 
@@ -94,9 +94,9 @@ defmodule MobilizonWeb.Resolvers.User do
         },
         _context
       ) do
-    with {:ok, user, _claims} <- MobilizonWeb.Guardian.resource_from_token(refresh_token),
+    with {:ok, user, _claims} <- Auth.Guardian.resource_from_token(refresh_token),
          {:ok, _old, {exchanged_token, _claims}} <-
-           MobilizonWeb.Guardian.exchange(refresh_token, ["access", "refresh"], "access"),
+           Auth.Guardian.exchange(refresh_token, ["access", "refresh"], "access"),
          {:ok, refresh_token} <- Users.generate_refresh_token(user) do
       {:ok, %{access_token: exchanged_token, refresh_token: refresh_token}}
     else
diff --git a/lib/mobilizon_web/router.ex b/lib/mobilizon_web/router.ex
index 2b92afe32..1f20cf162 100644
--- a/lib/mobilizon_web/router.ex
+++ b/lib/mobilizon_web/router.ex
@@ -6,7 +6,7 @@ defmodule MobilizonWeb.Router do
 
   pipeline :graphql do
     #    plug(:accepts, ["json"])
-    plug(MobilizonWeb.AuthPipeline)
+    plug(MobilizonWeb.Auth.Pipeline)
   end
 
   pipeline :well_known do
@@ -14,13 +14,13 @@ defmodule MobilizonWeb.Router do
   end
 
   pipeline :activity_pub_signature do
-    plug(Mobilizon.Federation.Plugs.HTTPSignatures)
-    plug(Mobilizon.Federation.Plugs.MappedSignatureToIdentity)
+    plug(MobilizonWeb.Plugs.HTTPSignatures)
+    plug(MobilizonWeb.Plugs.MappedSignatureToIdentity)
   end
 
   pipeline :relay do
-    plug(Mobilizon.Federation.Plugs.HTTPSignatures)
-    plug(Mobilizon.Federation.Plugs.MappedSignatureToIdentity)
+    plug(MobilizonWeb.Plugs.HTTPSignatures)
+    plug(MobilizonWeb.Plugs.MappedSignatureToIdentity)
     plug(:accepts, ["activity-json", "json"])
   end
 
@@ -58,7 +58,7 @@ defmodule MobilizonWeb.Router do
     )
   end
 
-  forward("/graphiql", Absinthe.Plug.GraphiQL, schema: MobilizonWeb.Schema)
+  ## FEDERATION
 
   scope "/.well-known", MobilizonWeb do
     pipe_through(:well_known)
@@ -69,28 +69,6 @@ defmodule MobilizonWeb.Router do
     get("/nodeinfo/:version", NodeInfoController, :nodeinfo)
   end
 
-  scope "/", MobilizonWeb do
-    pipe_through(:atom_and_ical)
-
-    get("/@:name/feed/:format", FeedController, :actor)
-    get("/events/:uuid/export/:format", FeedController, :event)
-    get("/events/going/:token/:format", FeedController, :going)
-  end
-
-  scope "/", MobilizonWeb do
-    pipe_through(:browser)
-
-    # Because the "/events/:uuid" route caches all these, we need to force them
-    get("/events/create", PageController, :index)
-    get("/events/list", PageController, :index)
-    get("/events/me", PageController, :index)
-    get("/events/explore", PageController, :index)
-    get("/events/:uuid/edit", PageController, :index)
-
-    # This is a hack to ease link generation into emails
-    get("/moderation/reports/:id", PageController, :index, as: "moderation_report")
-  end
-
   scope "/", MobilizonWeb do
     pipe_through(:activity_pub_and_html)
     pipe_through(:activity_pub_signature)
@@ -121,6 +99,34 @@ defmodule MobilizonWeb.Router do
     post("/inbox", ActivityPubController, :inbox)
   end
 
+  ## FEED
+
+  scope "/", MobilizonWeb do
+    pipe_through(:atom_and_ical)
+
+    get("/@:name/feed/:format", FeedController, :actor)
+    get("/events/:uuid/export/:format", FeedController, :event)
+    get("/events/going/:token/:format", FeedController, :going)
+  end
+
+  ## MOBILIZON
+
+  forward("/graphiql", Absinthe.Plug.GraphiQL, schema: MobilizonWeb.Schema)
+
+  scope "/", MobilizonWeb do
+    pipe_through(:browser)
+
+    # Because the "/events/:uuid" route caches all these, we need to force them
+    get("/events/create", PageController, :index)
+    get("/events/list", PageController, :index)
+    get("/events/me", PageController, :index)
+    get("/events/explore", PageController, :index)
+    get("/events/:uuid/edit", PageController, :index)
+
+    # This is a hack to ease link generation into emails
+    get("/moderation/reports/:id", PageController, :index, as: "moderation_report")
+  end
+
   scope "/proxy/", MobilizonWeb do
     pipe_through(:remote_media)
 
diff --git a/lib/mobilizon_web/schema/custom/UUID4.ex b/lib/mobilizon_web/schema/custom/uuid4.ex
similarity index 100%
rename from lib/mobilizon_web/schema/custom/UUID4.ex
rename to lib/mobilizon_web/schema/custom/uuid4.ex
diff --git a/lib/mobilizon_web/upload/filter.ex b/lib/mobilizon_web/upload/filter/filter.ex
similarity index 100%
rename from lib/mobilizon_web/upload/filter.ex
rename to lib/mobilizon_web/upload/filter/filter.ex
diff --git a/lib/mobilizon_web/mime.ex b/lib/mobilizon_web/upload/mime.ex
similarity index 98%
rename from lib/mobilizon_web/mime.ex
rename to lib/mobilizon_web/upload/mime.ex
index ac7ff627f..786c4e7fb 100644
--- a/lib/mobilizon_web/mime.ex
+++ b/lib/mobilizon_web/upload/mime.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/mime.ex
 
-defmodule MobilizonWeb.MIME do
+defmodule MobilizonWeb.Upload.MIME do
   @moduledoc """
   Returns the mime-type of a binary and optionally a normalized file-name.
   """
diff --git a/lib/mobilizon_web/upload.ex b/lib/mobilizon_web/upload/upload.ex
similarity index 95%
rename from lib/mobilizon_web/upload.ex
rename to lib/mobilizon_web/upload/upload.ex
index 5920ce586..6ddeb2f07 100644
--- a/lib/mobilizon_web/upload.ex
+++ b/lib/mobilizon_web/upload/upload.ex
@@ -27,7 +27,7 @@ defmodule MobilizonWeb.Upload do
 
   Related behaviors:
 
-  * `MobilizonWeb.Uploaders.Uploader`
+  * `MobilizonWeb.Upload.Uploader`
   * `MobilizonWeb.Upload.Filter`
 
   """
@@ -36,7 +36,7 @@ defmodule MobilizonWeb.Upload do
 
   alias Mobilizon.Config
 
-  alias MobilizonWeb.{MIME, Upload, Uploaders}
+  alias MobilizonWeb.Upload.{Filter, MIME, Uploader}
 
   require Logger
 
@@ -69,8 +69,8 @@ defmodule MobilizonWeb.Upload do
 
     with {:ok, upload} <- prepare_upload(upload, opts),
          upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"},
-         {:ok, upload} <- Upload.Filter.filter(opts.filters, upload),
-         {:ok, url_spec} <- Uploaders.Uploader.put_file(opts.uploader, upload) do
+         {:ok, upload} <- Filter.filter(opts.filters, upload),
+         {:ok, url_spec} <- Uploader.put_file(opts.uploader, upload) do
       {:ok,
        %{
          name: Map.get(opts, :description) || upload.name,
@@ -92,7 +92,7 @@ defmodule MobilizonWeb.Upload do
     with opts <- get_opts(opts),
          %URI{path: "/media/" <> path, host: host} <- URI.parse(url),
          {:same_host, true} <- {:same_host, host == MobilizonWeb.Endpoint.host()} do
-      Uploaders.Uploader.remove_file(opts.uploader, path)
+      Uploader.remove_file(opts.uploader, path)
     else
       %URI{} = _uri ->
         {:error, "URL doesn't match pattern"}
diff --git a/lib/mobilizon_web/uploaders/local.ex b/lib/mobilizon_web/upload/uploader/local.ex
similarity index 94%
rename from lib/mobilizon_web/uploaders/local.ex
rename to lib/mobilizon_web/upload/uploader/local.ex
index 4e5f0ea99..48ea0eb4e 100644
--- a/lib/mobilizon_web/uploaders/local.ex
+++ b/lib/mobilizon_web/upload/uploader/local.ex
@@ -3,12 +3,12 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/uploaders/local.ex
 
-defmodule MobilizonWeb.Uploaders.Local do
+defmodule MobilizonWeb.Upload.Uploader.Local do
   @moduledoc """
   Local uploader for files
   """
 
-  @behaviour MobilizonWeb.Uploaders.Uploader
+  @behaviour MobilizonWeb.Upload.Uploader
 
   alias Mobilizon.Config
 
diff --git a/lib/mobilizon_web/uploaders/uploader.ex b/lib/mobilizon_web/upload/uploader/uploader.ex
similarity index 98%
rename from lib/mobilizon_web/uploaders/uploader.ex
rename to lib/mobilizon_web/upload/uploader/uploader.ex
index 1f8d0fda4..eb02eecd5 100644
--- a/lib/mobilizon_web/uploaders/uploader.ex
+++ b/lib/mobilizon_web/upload/uploader/uploader.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 # Upstream: https://git.pleroma.social/pleroma/pleroma/blob/develop/lib/pleroma/uploaders/uploader.ex
 
-defmodule MobilizonWeb.Uploaders.Uploader do
+defmodule MobilizonWeb.Upload.Uploader do
   @moduledoc """
   Defines the contract to put and get an uploaded file to any backend.
   """
diff --git a/lib/federation/views/actor_view.ex b/lib/mobilizon_web/views/activity_pub/actor_view.ex
similarity index 100%
rename from lib/federation/views/actor_view.ex
rename to lib/mobilizon_web/views/activity_pub/actor_view.ex
diff --git a/lib/federation/views/object_view.ex b/lib/mobilizon_web/views/activity_pub/object_view.ex
similarity index 100%
rename from lib/federation/views/object_view.ex
rename to lib/mobilizon_web/views/activity_pub/object_view.ex
diff --git a/lib/service/admin/action_log.ex b/lib/service/admin/action_log.ex
deleted file mode 100644
index ebafaad8d..000000000
--- a/lib/service/admin/action_log.ex
+++ /dev/null
@@ -1,39 +0,0 @@
-defmodule Mobilizon.Service.Admin.ActionLog do
-  @moduledoc """
-  Module to handle action log creations.
-  """
-
-  alias Mobilizon.Actors.Actor
-  alias Mobilizon.{Admin, Users}
-  alias Mobilizon.Admin.ActionLog
-  alias Mobilizon.Users.User
-
-  @doc """
-  Log an admin action
-  """
-  @spec log_action(Actor.t(), String.t(), String.t()) :: {:ok, ActionLog.t()}
-  def log_action(%Actor{user_id: user_id, id: actor_id}, action, target) do
-    with %User{role: role} <- Users.get_user!(user_id),
-         {:role, true} <- {:role, role in [:administrator, :moderator]},
-         {:ok, %ActionLog{} = create_action_log} <-
-           Admin.create_action_log(%{
-             "actor_id" => actor_id,
-             "target_type" => to_string(target.__struct__),
-             "target_id" => target.id,
-             "action" => action,
-             "changes" => stringify_struct(target)
-           }) do
-      {:ok, create_action_log}
-    end
-  end
-
-  defp stringify_struct(%_{} = struct) do
-    association_fields = struct.__struct__.__schema__(:associations)
-
-    struct
-    |> Map.from_struct()
-    |> Map.drop(association_fields ++ [:__meta__])
-  end
-
-  defp stringify_struct(struct), do: struct
-end
diff --git a/lib/service/formatter/html.ex b/lib/service/formatter/html.ex
index 9eccbb217..705411041 100644
--- a/lib/service/formatter/html.ex
+++ b/lib/service/formatter/html.ex
@@ -14,4 +14,3 @@ defmodule Mobilizon.Service.Formatter.HTML do
 
   def filter_tags(html), do: Scrubber.scrub(html, DefaultScrubbler)
 end
-
diff --git a/lib/service/workers/helper.ex b/lib/service/workers/helper.ex
index 6f07ac0cc..713eb7095 100644
--- a/lib/service/workers/helper.ex
+++ b/lib/service/workers/helper.ex
@@ -9,6 +9,7 @@ defmodule Mobilizon.Service.Workers.Helper do
   """
 
   alias Mobilizon.Config
+  alias Mobilizon.Service.Workers.Helper
   alias Mobilizon.Storage.Repo
 
   def worker_args(queue) do
@@ -40,7 +41,7 @@ defmodule Mobilizon.Service.Workers.Helper do
       def enqueue(operation, params, worker_args \\ []) do
         params = Map.merge(%{"op" => operation}, params)
         queue_atom = String.to_existing_atom(unquote(queue))
-        worker_args = worker_args ++ __MODULE__.worker_args(queue_atom)
+        worker_args = worker_args ++ Helper.worker_args(queue_atom)
 
         unquote(caller_module)
         |> apply(:new, [params, worker_args])
diff --git a/mix.exs b/mix.exs
index 280cf590f..2d018b403 100644
--- a/mix.exs
+++ b/mix.exs
@@ -181,6 +181,8 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Actors.Member,
         Mobilizon.Addresses,
         Mobilizon.Addresses.Address,
+        Mobilizon.Admin,
+        Mobilizon.Admin.ActionLog,
         Mobilizon.Events,
         Mobilizon.Events.Event,
         Mobilizon.Events.Comment,
@@ -190,7 +192,7 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Events.Tag,
         Mobilizon.Events.TagRelations,
         Mobilizon.Events.Track,
-        Mobilizon.Event.EventCategory,
+        Mobilizon.Events.EventCategory,
         Mobilizon.Events.CommentVisibility,
         Mobilizon.Events.EventStatus,
         Mobilizon.Events.EventVisibility,
@@ -199,111 +201,184 @@ defmodule Mobilizon.Mixfile do
         Mobilizon.Events.Tag.TitleSlug,
         Mobilizon.Events.Tag.TitleSlug.Type,
         Mobilizon.Events.TagRelation,
+        Mobilizon.Media,
+        Mobilizon.Media.File,
+        Mobilizon.Media.Picture,
+        Mobilizon.Mention,
+        Mobilizon.Reports,
+        Mobilizon.Reports.Note,
+        Mobilizon.Reports.Report,
+        Mobilizon.Share,
+        Mobilizon.Tombstone,
         Mobilizon.Users,
         Mobilizon.Users.User,
         Mobilizon.Users.UserRole,
-        Mobilizon.Users.Guards,
-        Mobilizon.Storage.Ecto,
-        Mobilizon.Storage.Repo,
         Mobilizon.Federation.ActivityPub.Activity
       ],
       APIs: [
         MobilizonWeb.API.Comments,
         MobilizonWeb.API.Events,
+        MobilizonWeb.API.Follows,
         MobilizonWeb.API.Groups,
+        MobilizonWeb.API.Participations,
+        MobilizonWeb.API.Reports,
         MobilizonWeb.API.Search,
         MobilizonWeb.API.Utils
       ],
       Web: [
         MobilizonWeb,
-        MobilizonWeb.PageView,
+        MobilizonWeb.Endpoint,
         MobilizonWeb.Router,
         MobilizonWeb.Router.Helpers,
-        MobilizonWeb.AuthErrorHandler,
-        MobilizonWeb.AuthPipeline,
-        MobilizonWeb.Cache,
-        MobilizonWeb.ChangesetView,
-        MobilizonWeb.Context,
-        MobilizonWeb.Endpoint,
-        MobilizonWeb.ErrorHelpers,
-        MobilizonWeb.ErrorView,
+        MobilizonWeb.Plugs.UploadedMedia,
         MobilizonWeb.FallbackController,
         MobilizonWeb.FeedController,
-        MobilizonWeb.Gettext,
-        MobilizonWeb.Guardian,
-        MobilizonWeb.Guardian.Plug,
-        MobilizonWeb.JsonLD.ObjectView,
+        MobilizonWeb.MediaProxyController,
         MobilizonWeb.PageController,
-        MobilizonWeb.Uploaders.Avatar,
-        MobilizonWeb.Uploaders.Category,
-        MobilizonWeb.Uploaders.Category.Type
+        MobilizonWeb.ChangesetView,
+        MobilizonWeb.JsonLD.ObjectView,
+        MobilizonWeb.EmailView,
+        MobilizonWeb.ErrorHelpers,
+        MobilizonWeb.ErrorView,
+        MobilizonWeb.LayoutView,
+        MobilizonWeb.PageView,
+        MobilizonWeb.Auth.Context,
+        MobilizonWeb.Auth.ErrorHandler,
+        MobilizonWeb.Auth.Guardian,
+        MobilizonWeb.Auth.Pipeline,
+        MobilizonWeb.Cache,
+        MobilizonWeb.Cache.ActivityPub,
+        MobilizonWeb.Email,
+        MobilizonWeb.Email.Admin,
+        MobilizonWeb.Email.Checker,
+        MobilizonWeb.Email.Event,
+        MobilizonWeb.Email.Mailer,
+        MobilizonWeb.Email.Participation,
+        MobilizonWeb.Email.User,
+        MobilizonWeb.Upload,
+        MobilizonWeb.Upload.Filter,
+        MobilizonWeb.Upload.Filter.AnonymizeFilename,
+        MobilizonWeb.Upload.Filter.Dedupe,
+        MobilizonWeb.Upload.Filter.Mogrify,
+        MobilizonWeb.Upload.Filter.Optimize,
+        MobilizonWeb.Upload.MIME,
+        MobilizonWeb.Upload.Uploader,
+        MobilizonWeb.Upload.Uploader.Local,
+        MobilizonWeb.MediaProxy,
+        MobilizonWeb.ReverseProxy
       ],
       Geospatial: [
         Mobilizon.Service.Geospatial,
         Mobilizon.Service.Geospatial.Addok,
         Mobilizon.Service.Geospatial.GoogleMaps,
         Mobilizon.Service.Geospatial.MapQuest,
+        Mobilizon.Service.Geospatial.Mimirsbrunn,
         Mobilizon.Service.Geospatial.Nominatim,
+        Mobilizon.Service.Geospatial.Pelias,
         Mobilizon.Service.Geospatial.Photon,
         Mobilizon.Service.Geospatial.Provider
       ],
+      Localization: [
+        Mobilizon.Cldr,
+        MobilizonWeb.Gettext
+      ],
       GraphQL: [
+        MobilizonWeb.GraphQLSocket,
         MobilizonWeb.Resolvers.Address,
+        MobilizonWeb.Resolvers.Admin,
         MobilizonWeb.Resolvers.Comment,
+        MobilizonWeb.Resolvers.Config,
         MobilizonWeb.Resolvers.Event,
         MobilizonWeb.Resolvers.FeedToken,
         MobilizonWeb.Resolvers.Group,
+        MobilizonWeb.Resolvers.Member,
         MobilizonWeb.Resolvers.Person,
+        MobilizonWeb.Resolvers.Picture,
+        MobilizonWeb.Resolvers.Report,
         MobilizonWeb.Resolvers.Search,
         MobilizonWeb.Resolvers.Tag,
         MobilizonWeb.Resolvers.User,
         MobilizonWeb.Schema,
         MobilizonWeb.Schema.ActorInterface,
+        MobilizonWeb.Schema.Actors.ApplicationType,
         MobilizonWeb.Schema.Actors.FollowerType,
         MobilizonWeb.Schema.Actors.GroupType,
         MobilizonWeb.Schema.Actors.MemberType,
         MobilizonWeb.Schema.Actors.PersonType,
         MobilizonWeb.Schema.AddressType,
+        MobilizonWeb.Schema.AdminType,
         MobilizonWeb.Schema.CommentType,
-        MobilizonWeb.Schema.Custom.Point,
-        MobilizonWeb.Schema.Custom.UUID,
+        MobilizonWeb.Schema.ConfigType,
         MobilizonWeb.Schema.EventType,
         MobilizonWeb.Schema.Events.FeedTokenType,
         MobilizonWeb.Schema.Events.ParticipantType,
+        MobilizonWeb.Schema.PictureType,
+        MobilizonWeb.Schema.ReportType,
+        MobilizonWeb.Schema.SearchType,
         MobilizonWeb.Schema.SortType,
         MobilizonWeb.Schema.TagType,
         MobilizonWeb.Schema.UserType,
-        MobilizonWeb.Schema.Utils
+        MobilizonWeb.Schema.Utils,
+        MobilizonWeb.Schema.Custom.Point,
+        MobilizonWeb.Schema.Custom.UUID
       ],
       ActivityPub: [
         Mobilizon.Federation.ActivityPub,
+        Mobilizon.Federation.ActivityPub.Audience,
         Mobilizon.Federation.ActivityPub.Federator,
+        Mobilizon.Federation.ActivityPub.Relay,
         Mobilizon.Federation.ActivityPub.Transmogrifier,
+        Mobilizon.Federation.ActivityPub.Visibility,
         Mobilizon.Federation.ActivityPub.Utils,
+        Mobilizon.Federation.ActivityStream.Convertible,
+        Mobilizon.Federation.ActivityStream.Converter,
+        Mobilizon.Federation.ActivityStream.Converter.Actor,
+        Mobilizon.Federation.ActivityStream.Converter.Address,
+        Mobilizon.Federation.ActivityStream.Converter.Comment,
+        Mobilizon.Federation.ActivityStream.Converter.Event,
+        Mobilizon.Federation.ActivityStream.Converter.Flag,
+        Mobilizon.Federation.ActivityStream.Converter.Follower,
+        Mobilizon.Federation.ActivityStream.Converter.Participant,
+        Mobilizon.Federation.ActivityStream.Converter.Picture,
+        Mobilizon.Federation.ActivityStream.Converter.Tombstone,
+        Mobilizon.Federation.ActivityStream.Converter.Utils,
         Mobilizon.Federation.HTTPSignatures.Signature,
         Mobilizon.Federation.WebFinger,
         Mobilizon.Federation.WebFinger.XmlBuilder,
-        Mobilizon.Federation.Plugs.HTTPSignatures,
-        MobilizonWeb.ActivityPub.ActorView,
-        MobilizonWeb.ActivityPub.ObjectView,
+        MobilizonWeb.Plugs.Federating,
+        MobilizonWeb.Plugs.HTTPSignatures,
+        MobilizonWeb.Plugs.MappedSignatureToIdentity,
         MobilizonWeb.ActivityPubController,
+        MobilizonWeb.NodeInfoController,
         MobilizonWeb.WebFingerController,
-        MobilizonWeb.NodeInfoController
+        MobilizonWeb.ActivityPub.ActorView,
+        MobilizonWeb.ActivityPub.ObjectView
       ],
       Services: [
-        Mobilizon.Service.EmailChecker,
         Mobilizon.Service.Export.Feed,
         Mobilizon.Service.Export.ICalendar,
-        Mobilizon.Service.Metadata,
         Mobilizon.Service.Formatter,
-        Mobilizon.Service.Users.Tools
+        Mobilizon.Service.Formatter.HTML,
+        Mobilizon.Service.Formatter.DefaultScrubbler,
+        Mobilizon.Service.Metadata,
+        Mobilizon.Service.Metadata.Actor,
+        Mobilizon.Service.Metadata.Comment,
+        Mobilizon.Service.Metadata.Event,
+        Mobilizon.Service.Metadata.Instance,
+        Mobilizon.Service.Metadata.Utils,
+        Mobilizon.Service.Statistics,
+        Mobilizon.Service.Workers.Background,
+        Mobilizon.Service.Workers.BuildSearch,
+        Mobilizon.Service.Workers.Helper
       ],
       Tools: [
         Mobilizon.Application,
+        Mobilizon.Config,
+        Mobilizon.Crypto,
         Mobilizon.Factory,
-        MobilizonWeb.Email.Mailer,
-        MobilizonWeb.Email.User,
-        MobilizonWeb.EmailView
+        Mobilizon.Storage.Ecto,
+        Mobilizon.Storage.Page,
+        Mobilizon.Storage.Repo
       ]
     ]
   end
diff --git a/test/mobilizon/actors/actors_test.exs b/test/mobilizon/actors/actors_test.exs
index a6f1d5828..0d4e5c80a 100644
--- a/test/mobilizon/actors/actors_test.exs
+++ b/test/mobilizon/actors/actors_test.exs
@@ -14,6 +14,8 @@ defmodule Mobilizon.ActorsTest do
 
   alias Mobilizon.Federation.ActivityPub
 
+  alias MobilizonWeb.Upload.Uploader
+
   describe "actors" do
     @valid_attrs %{
       summary: "some description",
@@ -241,12 +243,12 @@ defmodule Mobilizon.ActorsTest do
       %URI{path: "/media/" <> banner_path} = URI.parse(banner_url)
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> avatar_path
              )
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> banner_path
              )
 
@@ -271,12 +273,12 @@ defmodule Mobilizon.ActorsTest do
       refute actor.suspended
 
       refute File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> avatar_path
              )
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> banner_path
              )
     end
@@ -300,12 +302,12 @@ defmodule Mobilizon.ActorsTest do
       %URI{path: "/media/" <> banner_path} = URI.parse(banner_url)
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> avatar_path
              )
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> banner_path
              )
 
@@ -334,12 +336,12 @@ defmodule Mobilizon.ActorsTest do
       assert %Tombstone{} = Tombstone.find_tombstone(comment1_url)
 
       refute File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> avatar_path
              )
 
       refute File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> banner_path
              )
     end
diff --git a/test/service/admin/action_log_test.exs b/test/mobilizon/admin/action_log_test.exs
similarity index 88%
rename from test/service/admin/action_log_test.exs
rename to test/mobilizon/admin/action_log_test.exs
index 5b6d61e07..200c54fc1 100644
--- a/test/service/admin/action_log_test.exs
+++ b/test/mobilizon/admin/action_log_test.exs
@@ -6,8 +6,8 @@ defmodule Mobilizon.Service.Admin.ActionLogTest do
   use Mobilizon.DataCase
 
   import Mobilizon.Factory
-  import Mobilizon.Service.Admin.ActionLog
 
+  alias Mobilizon.Admin
   alias Mobilizon.Admin.ActionLog
   alias Mobilizon.Reports.{Note, Report}
 
@@ -27,7 +27,7 @@ defmodule Mobilizon.Service.Admin.ActionLogTest do
                 target_id: report_id,
                 action: :update,
                 actor: moderator
-              }} = log_action(moderator, "update", report)
+              }} = Admin.log_action(moderator, "update", report)
     end
 
     test "log the creation of a report note", %{moderator: moderator} do
@@ -40,7 +40,7 @@ defmodule Mobilizon.Service.Admin.ActionLogTest do
                 target_id: note_id,
                 action: :create,
                 actor: moderator
-              }} = log_action(moderator, "create", report)
+              }} = Admin.log_action(moderator, "create", report)
     end
   end
 end
diff --git a/test/mobilizon/media/media_test.exs b/test/mobilizon/media/media_test.exs
index 2fb5e3f21..bb16b8b17 100644
--- a/test/mobilizon/media/media_test.exs
+++ b/test/mobilizon/media/media_test.exs
@@ -5,6 +5,8 @@ defmodule Mobilizon.MediaTest do
 
   alias Mobilizon.{Config, Media}
 
+  alias MobilizonWeb.Upload.Uploader
+
   describe "media" do
     setup [:ensure_local_uploader]
     alias Mobilizon.Media.Picture
@@ -49,7 +51,7 @@ defmodule Mobilizon.MediaTest do
       %URI{path: "/media/" <> path} = URI.parse(picture.file.url)
 
       assert File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> path
              )
 
@@ -57,7 +59,7 @@ defmodule Mobilizon.MediaTest do
       assert_raise Ecto.NoResultsError, fn -> Media.get_picture!(picture.id) end
 
       refute File.exists?(
-               Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+               Config.get!([Uploader.Local, :uploads]) <>
                  "/" <> path
              )
     end
diff --git a/test/federation/plugs/federating_plug_test.exs b/test/mobilizon_web/plugs/federating_test.exs
similarity index 87%
rename from test/federation/plugs/federating_plug_test.exs
rename to test/mobilizon_web/plugs/federating_test.exs
index 8eaac9f02..9d7045465 100644
--- a/test/federation/plugs/federating_plug_test.exs
+++ b/test/mobilizon_web/plugs/federating_test.exs
@@ -3,10 +3,10 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule Mobilizon.Federation.Plug.FederatingTest do
+defmodule MobilizonWeb.Plug.FederatingTest do
   use MobilizonWeb.ConnCase
 
-  alias Mobilizon.Federation.Plugs.Federating
+  alias MobilizonWeb.Plugs.Federating
 
   test "returns and halt the conn when federating is disabled" do
     Mobilizon.Config.put([:instance, :federating], false)
diff --git a/test/federation/plugs/mapped_identity_to_signature_plug_test.exs b/test/mobilizon_web/plugs/mapped_identity_to_signature_test.exs
similarity index 96%
rename from test/federation/plugs/mapped_identity_to_signature_plug_test.exs
rename to test/mobilizon_web/plugs/mapped_identity_to_signature_test.exs
index 27ab2b6fd..1a24ea866 100644
--- a/test/federation/plugs/mapped_identity_to_signature_plug_test.exs
+++ b/test/mobilizon_web/plugs/mapped_identity_to_signature_test.exs
@@ -3,7 +3,7 @@
 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
-defmodule Mobilizon.Federation.Plugs.MappedSignatureToIdentityTest do
+defmodule MobilizonWeb.Plugs.MappedSignatureToIdentityTest do
   use MobilizonWeb.ConnCase
   use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
 
diff --git a/test/mobilizon_web/plugs/uploaded_media_plug_test.exs b/test/mobilizon_web/plugs/uploaded_media_test.exs
similarity index 100%
rename from test/mobilizon_web/plugs/uploaded_media_plug_test.exs
rename to test/mobilizon_web/plugs/uploaded_media_test.exs
diff --git a/test/mobilizon_web/media_proxy_test.exs b/test/mobilizon_web/proxy/media_proxy_test.exs
similarity index 100%
rename from test/mobilizon_web/media_proxy_test.exs
rename to test/mobilizon_web/proxy/media_proxy_test.exs
diff --git a/test/mobilizon_web/resolvers/address_resolver_test.exs b/test/mobilizon_web/resolvers/address_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/address_resolver_test.exs
rename to test/mobilizon_web/resolvers/address_test.exs
diff --git a/test/mobilizon_web/resolvers/admin_resolver_test.exs b/test/mobilizon_web/resolvers/admin_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/admin_resolver_test.exs
rename to test/mobilizon_web/resolvers/admin_test.exs
diff --git a/test/mobilizon_web/resolvers/comment_resolver_test.exs b/test/mobilizon_web/resolvers/comment_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/comment_resolver_test.exs
rename to test/mobilizon_web/resolvers/comment_test.exs
diff --git a/test/mobilizon_web/resolvers/config_resolver_test.exs b/test/mobilizon_web/resolvers/config_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/config_resolver_test.exs
rename to test/mobilizon_web/resolvers/config_test.exs
diff --git a/test/mobilizon_web/resolvers/event_resolver_test.exs b/test/mobilizon_web/resolvers/event_test.exs
similarity index 99%
rename from test/mobilizon_web/resolvers/event_resolver_test.exs
rename to test/mobilizon_web/resolvers/event_test.exs
index 44ae7dce0..efa54a9ea 100644
--- a/test/mobilizon_web/resolvers/event_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/event_test.exs
@@ -158,7 +158,11 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
 
       assert json_response(res, 200)["data"]["createEvent"]["title"] == "come to my event"
       {id, ""} = json_response(res, 200)["data"]["createEvent"]["id"] |> Integer.parse()
-      assert_enqueued(worker: Workers.BuildSearch, args: %{event_id: id, op: :insert_search_event})
+
+      assert_enqueued(
+        worker: Workers.BuildSearch,
+        args: %{event_id: id, op: :insert_search_event}
+      )
     end
 
     test "create_event/3 creates an event and escapes title and description", %{
@@ -204,7 +208,11 @@ defmodule MobilizonWeb.Resolvers.EventResolverTest do
                "<b>My description</b> <img src=\"http://placekitten.com/g/200/300\" />"
 
       {id, ""} = res["data"]["createEvent"]["id"] |> Integer.parse()
-      assert_enqueued(worker: Workers.BuildSearch, args: %{event_id: id, op: :insert_search_event})
+
+      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
diff --git a/test/mobilizon_web/resolvers/feed_token_resolver_test.exs b/test/mobilizon_web/resolvers/feed_token_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/feed_token_resolver_test.exs
rename to test/mobilizon_web/resolvers/feed_token_test.exs
diff --git a/test/mobilizon_web/resolvers/group_resolver_test.exs b/test/mobilizon_web/resolvers/group_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/group_resolver_test.exs
rename to test/mobilizon_web/resolvers/group_test.exs
diff --git a/test/mobilizon_web/resolvers/member_resolver_test.exs b/test/mobilizon_web/resolvers/member_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/member_resolver_test.exs
rename to test/mobilizon_web/resolvers/member_test.exs
diff --git a/test/mobilizon_web/resolvers/participant_resolver_test.exs b/test/mobilizon_web/resolvers/participant_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/participant_resolver_test.exs
rename to test/mobilizon_web/resolvers/participant_test.exs
diff --git a/test/mobilizon_web/resolvers/person_resolver_test.exs b/test/mobilizon_web/resolvers/person_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/person_resolver_test.exs
rename to test/mobilizon_web/resolvers/person_test.exs
diff --git a/test/mobilizon_web/resolvers/picture_resolver_test.exs b/test/mobilizon_web/resolvers/picture_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/picture_resolver_test.exs
rename to test/mobilizon_web/resolvers/picture_test.exs
diff --git a/test/mobilizon_web/resolvers/report_resolver_test.exs b/test/mobilizon_web/resolvers/report_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/report_resolver_test.exs
rename to test/mobilizon_web/resolvers/report_test.exs
diff --git a/test/mobilizon_web/resolvers/search_resolver_test.exs b/test/mobilizon_web/resolvers/search_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/search_resolver_test.exs
rename to test/mobilizon_web/resolvers/search_test.exs
diff --git a/test/mobilizon_web/resolvers/tag_resolver_test.exs b/test/mobilizon_web/resolvers/tag_test.exs
similarity index 100%
rename from test/mobilizon_web/resolvers/tag_resolver_test.exs
rename to test/mobilizon_web/resolvers/tag_test.exs
diff --git a/test/mobilizon_web/resolvers/user_resolver_test.exs b/test/mobilizon_web/resolvers/user_test.exs
similarity index 95%
rename from test/mobilizon_web/resolvers/user_resolver_test.exs
rename to test/mobilizon_web/resolvers/user_test.exs
index 643b714ae..e0dd8194f 100644
--- a/test/mobilizon_web/resolvers/user_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/user_test.exs
@@ -5,10 +5,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
 
   use Bamboo.Test
 
-  alias Mobilizon.{Actors, Users}
+  alias Mobilizon.{Actors, Config, Users}
   alias Mobilizon.Actors.Actor
-  alias Mobilizon.Service.Users.ResetPassword
-  alias Mobilizon.Users
   alias Mobilizon.Users.User
 
   alias MobilizonWeb.{AbsintheHelpers, Email}
@@ -321,8 +319,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
     end
 
     test "create_user/3 doesn't allow registration when registration is closed", %{conn: conn} do
-      Mobilizon.Config.put([:instance, :registrations_open], false)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], [])
+      Config.put([:instance, :registrations_open], false)
+      Config.put([:instance, :registration_email_whitelist], [])
 
       mutation = """
           mutation createUser($email: String!, $password: String!) {
@@ -344,14 +342,14 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
         )
 
       assert hd(res["errors"])["message"] == "Registrations are not enabled"
-      Mobilizon.Config.put([:instance, :registrations_open], true)
+      Config.put([:instance, :registrations_open], true)
     end
 
     test "create_user/3 doesn't allow registration when user email is not on the whitelist", %{
       conn: conn
     } do
-      Mobilizon.Config.put([:instance, :registrations_open], false)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], ["random.org"])
+      Config.put([:instance, :registrations_open], false)
+      Config.put([:instance, :registration_email_whitelist], ["random.org"])
 
       mutation = """
           mutation createUser($email: String!, $password: String!) {
@@ -373,15 +371,15 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
         )
 
       assert hd(res["errors"])["message"] == "Your email is not on the whitelist"
-      Mobilizon.Config.put([:instance, :registrations_open], true)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], [])
+      Config.put([:instance, :registrations_open], true)
+      Config.put([:instance, :registration_email_whitelist], [])
     end
 
     test "create_user/3 allows registration when user email domain is on the whitelist", %{
       conn: conn
     } do
-      Mobilizon.Config.put([:instance, :registrations_open], false)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], ["demo.tld"])
+      Config.put([:instance, :registrations_open], false)
+      Config.put([:instance, :registration_email_whitelist], ["demo.tld"])
 
       mutation = """
           mutation createUser($email: String!, $password: String!) {
@@ -404,13 +402,13 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
 
       refute res["errors"]
       assert res["data"]["createUser"]["email"] == @user_creation.email
-      Mobilizon.Config.put([:instance, :registrations_open], true)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], [])
+      Config.put([:instance, :registrations_open], true)
+      Config.put([:instance, :registration_email_whitelist], [])
     end
 
     test "create_user/3 allows registration when user email is on the whitelist", %{conn: conn} do
-      Mobilizon.Config.put([:instance, :registrations_open], false)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], [@user_creation.email])
+      Config.put([:instance, :registrations_open], false)
+      Config.put([:instance, :registration_email_whitelist], [@user_creation.email])
 
       mutation = """
           mutation createUser($email: String!, $password: String!) {
@@ -433,8 +431,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
 
       refute res["errors"]
       assert res["data"]["createUser"]["email"] == @user_creation.email
-      Mobilizon.Config.put([:instance, :registrations_open], true)
-      Mobilizon.Config.put([:instance, :registration_email_whitelist], [])
+      Config.put([:instance, :registrations_open], true)
+      Config.put([:instance, :registration_email_whitelist], [])
     end
 
     test "register_person/3 doesn't register a profile from an unknown email", context do
@@ -637,7 +635,7 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
                "You requested again a confirmation email too soon"
 
       # Hammer time !
-      Mobilizon.Users.update_user(user, %{
+      Users.update_user(user, %{
         confirmation_sent_at: Timex.shift(user.confirmation_sent_at, hours: -3)
       })
 
@@ -709,8 +707,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
     test "test reset_password/3 with valid email", context do
       {:ok, %User{} = user} = Users.register(%{email: "toto@tata.tld", password: "p4ssw0rd"})
       %Actor{} = insert(:actor, user: user)
-      {:ok, _email_sent} = ResetPassword.send_password_reset_email(user)
-      %User{reset_password_token: reset_password_token} = Mobilizon.Users.get_user!(user.id)
+      {:ok, _email_sent} = Email.User.send_password_reset_email(user)
+      %User{reset_password_token: reset_password_token} = Users.get_user!(user.id)
 
       mutation = """
           mutation {
@@ -734,8 +732,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
 
     test "test reset_password/3 with a password too short", context do
       %User{} = user = insert(:user)
-      {:ok, _email_sent} = ResetPassword.send_password_reset_email(user)
-      %User{reset_password_token: reset_password_token} = Mobilizon.Users.get_user!(user.id)
+      {:ok, _email_sent} = Email.User.send_password_reset_email(user)
+      %User{reset_password_token: reset_password_token} = Users.get_user!(user.id)
 
       mutation = """
           mutation {
@@ -760,8 +758,8 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
 
     test "test reset_password/3 with an invalid token", context do
       %User{} = user = insert(:user)
-      {:ok, _email_sent} = ResetPassword.send_password_reset_email(user)
-      %User{} = Mobilizon.Users.get_user!(user.id)
+      {:ok, _email_sent} = Email.User.send_password_reset_email(user)
+      %User{} = Users.get_user!(user.id)
 
       mutation = """
           mutation {
diff --git a/test/mobilizon_web/upload_test.exs b/test/mobilizon_web/upload/upload_test.exs
similarity index 97%
rename from test/mobilizon_web/upload_test.exs
rename to test/mobilizon_web/upload/upload_test.exs
index c5553adcb..78f2187ed 100644
--- a/test/mobilizon_web/upload_test.exs
+++ b/test/mobilizon_web/upload/upload_test.exs
@@ -9,6 +9,7 @@ defmodule Mobilizon.UploadTest do
   alias Mobilizon.Config
 
   alias MobilizonWeb.Upload
+  alias MobilizonWeb.Upload.Uploader
 
   describe "Storing a file with the Local uploader" do
     setup [:ensure_local_uploader]
@@ -184,7 +185,7 @@ defmodule Mobilizon.UploadTest do
 
     test "delete a not existing file" do
       file =
-        Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <>
+        Config.get!([Uploader.Local, :uploads]) <>
           "/not_existing/definitely.jpg"
 
       refute File.exists?(file)
@@ -214,6 +215,6 @@ defmodule Mobilizon.UploadTest do
     assert String.starts_with?(url, MobilizonWeb.Endpoint.url() <> "/media/")
 
     %URI{path: "/media/" <> path} = URI.parse(url)
-    {Config.get!([MobilizonWeb.Uploaders.Local, :uploads]) <> "/" <> path, url}
+    {Config.get!([Uploader.Local, :uploads]) <> "/" <> path, url}
   end
 end
diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex
index 4c10b2d58..18685ea98 100644
--- a/test/support/conn_case.ex
+++ b/test/support/conn_case.ex
@@ -30,7 +30,7 @@ defmodule MobilizonWeb.ConnCase do
       @endpoint MobilizonWeb.Endpoint
 
       def auth_conn(%Plug.Conn{} = conn, %User{} = user) do
-        {:ok, token, _claims} = MobilizonWeb.Guardian.encode_and_sign(user)
+        {:ok, token, _claims} = MobilizonWeb.Auth.Guardian.encode_and_sign(user)
 
         conn
         |> Plug.Conn.put_req_header("authorization", "Bearer #{token}")
diff --git a/test/support/data_case.ex b/test/support/data_case.ex
index 30d0d2609..886ef2e29 100644
--- a/test/support/data_case.ex
+++ b/test/support/data_case.ex
@@ -19,6 +19,9 @@ defmodule Mobilizon.DataCase do
   alias Mobilizon.Config
   alias Mobilizon.Storage.Repo
 
+  alias MobilizonWeb.Upload
+  alias MobilizonWeb.Upload.Uploader
+
   using do
     quote do
       alias Mobilizon.Storage.Repo
@@ -55,16 +58,16 @@ defmodule Mobilizon.DataCase do
   end
 
   def ensure_local_uploader(_context) do
-    uploader = Config.get([MobilizonWeb.Upload, :uploader])
-    filters = Config.get([MobilizonWeb.Upload, :filters])
+    uploader = Config.get([Upload, :uploader])
+    filters = Config.get([Upload, :filters])
 
-    unless uploader == MobilizonWeb.Uploaders.Local || filters != [] do
-      Config.put([MobilizonWeb.Upload, :uploader], MobilizonWeb.Uploaders.Local)
-      Config.put([MobilizonWeb.Upload, :filters], [])
+    unless uploader == Uploader.Local || filters != [] do
+      Config.put([Upload, :uploader], Uploader.Local)
+      Config.put([Upload, :filters], [])
 
       on_exit(fn ->
-        Config.put([MobilizonWeb.Upload, :uploader], uploader)
-        Config.put([MobilizonWeb.Upload, :filters], filters)
+        Config.put([Upload, :uploader], uploader)
+        Config.put([Upload, :filters], filters)
       end)
     end
 
diff --git a/test/tasks/users_test.exs b/test/tasks/users_test.exs
index 812666c90..d5165405f 100644
--- a/test/tasks/users_test.exs
+++ b/test/tasks/users_test.exs
@@ -1,10 +1,11 @@
 defmodule Mix.Tasks.Mobilizon.UsersTest do
   use Mobilizon.DataCase
 
+  import Mobilizon.Factory
+
   alias Mobilizon.Users
   alias Mobilizon.Users.User
   alias Mix.Tasks.Mobilizon.Users.{New, Delete, Show, Modify}
-  import Mobilizon.Factory
 
   Mix.shell(Mix.Shell.Process)