Merge branch 'fix-config-cache' into 'main'

fix(backend): fix config cache not being used everytime

See merge request framasoft/mobilizon!1433
This commit is contained in:
Thomas Citharel 2023-08-18 11:41:06 +00:00
commit 52b3e5b151
32 changed files with 1013 additions and 966 deletions

View file

@ -1,45 +1,20 @@
02CE4963DFD1B0D6D5C567357CAFFE97
155A1FB53DE39EC8EFCFD7FB94EA823D
2262742E5C8944D5BF6698EC61F5DE50
25BEE162A99754480967216281E9EF33
2A6F71CD6F1246F0B152C2376E2E398A
30552A09D485A6AA73401C1D54F63C21
52900CE4EE3598F6F178A651FB256770
6151F44368FC19F2394274F513C29151
765526195D4C6D770EAF4DC944A8CBF4
B2FF1A12F13B873507C85091688C1D6D
B9AF8A342CD7FF39E10CC10A408C28E1
C042E87389F7BDCFF4E076E95731AE69
C42BFAEF7100F57BED75998B217C857A
D11958E86F1B6D37EF656B63405CA8A4
F16F054F2628609A726B9FF2F089D484
26E816A7B054CB0347A2C6451F03B92B
2B76BDDB2BB4D36D69FAE793EBD63894
301A837DE24C6AEE1DA812DF9E5486C1
395A2740CB468F93F6EBE6E90EE08291
4013C9866943B9381D9F9F97027F88A9
4C796DD588A4B1C98E86BBCD0349949A
51289D8D7BDB59CB6473E0DED0591ED7
5A70DC86895DB3610C605EA9F31ED300
705C17F9C852F546D886B20DB2C4D0D1
75D2074B6F771BA8C032008EC18CABDF
7B1C6E35A374C38FF5F07DBF23B3EAE2
955ACF52ADD8FCAA450FB8138CB1FD1A
A092A563729E1F2C1C8D5D809A31F754
BFA12FDEDEAD7DEAB6D44DF6FDFBD5E1
D9A08930F140F9BA494BB90B3F812C87
FE1EEB91EA633570F703B251AE2D4D4E
02B15A0FE85181E2470E4E1E6740DFF6
128653EA565172F81FD177D1D6491CF3
2EB031217231C480C89EA0C1576EF3CA
39CFFBCF3FD4F6DB0E4DE4A9A78D3961
40C6EAD7C05ABB6A85BB904589DEF72F
49DE9560D506F9E7EF3AFD8DA6E5564B
759F752FA0768CCC7871895DC2A5CD51
7EEC79571F3F7CEEB04A8B86D908382A
E7967805C1EA5301F2722C7BDB2F25F3
BDFB0FB1AAF69C18212CBCFD42F8B717
40220A533CCACB3A1CE9DBF1A8A430A1
EEB29D1DDA3A3015BC645A989B5BD38E
5AEE3C678C80E0389C3B0D9D11886EB6
1C29EE70E90ECED01AF28EC58D2575B5
31CE26BC979C57B9E3CC97B40C290CE5
3529E7A4CECC24D02678820E6F521162
4A4B7002DEB734A943B467DF7D2BD1AA
4E7C044C59E0BCB76AA826789998F624
53CBBEB6243FAF5C37249CBA17DE6F4C
5BCE3651A03711295046DE48BDFE007E
630C0972985257251EDF89A7117DE423
8274AF29B81EC7CF7F585D5EED8A64E1
94ACF7B17C3FF42F64E57DD1DA936BD8
A32E125003F1EDFAD95C487C6A969725
ACF6272A1DBB3A2ABD96C0C120B5CA69
C46C4893B2F702ACADC4CAA5683FE370
CDF2CCE0CF10F49CDFAE22FE26208155
E720CB13C50FF3ADEE7C522531E11217
E8FC5F2C5DEA6671BA596B022C4FE6F2
F3D5851D3FB050939841ED2F14307A27
FD1C9756370A195B74E95CE504C45E9E

View file

@ -1,9 +1,9 @@
FROM elixir:latest
LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
ENV REFRESHED_AT=2023-05-22
ENV REFRESHED_AT=2023-08-17
RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool python3-pip python3-setuptools
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash && apt-get install nodejs -yq
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash && apt-get install nodejs -yq
RUN npm install -g yarn wait-on
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN mix local.hex --force && mix local.rebar --force

View file

@ -117,7 +117,7 @@
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/test-utils": "^2.0.2",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^9.3.0",

File diff suppressed because it is too large Load diff

View file

@ -273,7 +273,6 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do
|> Enum.into(%{}),
:ok <- eventually_update_instance_actor(res) do
Config.clear_config_cache()
Cachex.put(:config, :admin_config, res)
{:ok, res}
end

View file

@ -12,7 +12,6 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
"""
@spec get_config(any(), map(), Absinthe.Resolution.t()) :: {:ok, map()}
def get_config(_parent, _params, %{context: %{ip: ip}}) do
# ip = "2a01:e0a:184:2000:1112:e19d:9779:88c8"
geolix = Geolix.lookup(ip)
country_code =

View file

@ -190,7 +190,10 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
description: "The page in the paginated activity items list"
)
arg(:limit, :integer, default_value: 10, description: "The limit of activity items per page")
arg(:limit, :integer,
default_value: 10,
description: "The limit of activity items per page"
)
arg(:type, :activity_type, description: "Filter by type of activity")
arg(:author, :activity_author, description: "Filter by activity author")
@ -213,7 +216,9 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
enum :openness do
value(:invite_only, description: "The actor can only be followed by invitation")
value(:moderated, description: "The actor needs to accept the following before it's effective")
value(:moderated,
description: "The actor needs to accept the following before it's effective"
)
value(:open, description: "The actor is open to followings")
end

View file

@ -26,7 +26,9 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
resolve: &Person.user_for_person/3
)
field(:member_of, list_of(:member), description: "The list of groups this person is member of")
field(:member_of, list_of(:member),
description: "The list of groups this person is member of"
)
field(:url, :string, description: "The ActivityPub actor's URL")
field(:type, :actor_type, description: "The type of Actor (Person, Group,…)")
@ -94,7 +96,10 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
description: "The page in the paginated participation list"
)
arg(:limit, :integer, default_value: 10, description: "The limit of participations per page")
arg(:limit, :integer,
default_value: 10,
description: "The limit of participations per page"
)
resolve(&Person.person_participations/3)
end
@ -218,7 +223,10 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
field :create_person, :person do
arg(:preferred_username, non_null(:string), description: "The username for the profile")
arg(:name, :string, description: "The displayed name for the new profile", default_value: "")
arg(:name, :string,
description: "The displayed name for the new profile",
default_value: ""
)
arg(:summary, :string, description: "The summary for the new profile", default_value: "")
@ -286,7 +294,10 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
field :register_person, :person do
arg(:preferred_username, non_null(:string), description: "The username for the profile")
arg(:name, :string, description: "The displayed name for the new profile", default_value: "")
arg(:name, :string,
description: "The displayed name for the new profile",
default_value: ""
)
arg(:summary, :string, description: "The summary for the new profile", default_value: "")
arg(:email, non_null(:string), description: "The email from the user previously created")
@ -301,7 +312,11 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
"The banner for the profile, either as an object or directly the ID of an existing media"
)
middleware(Rajska.QueryAuthorization, permit: :all, scope: Mobilizon.Actors.Actor, args: %{})
middleware(Rajska.QueryAuthorization,
permit: :all,
scope: Mobilizon.Actors.Actor,
args: %{}
)
resolve(&Person.register_person/3)
end

View file

@ -102,7 +102,10 @@ defmodule Mobilizon.GraphQL.Schema.AddressType do
description: "The page in the paginated search results list"
)
arg(:limit, :integer, default_value: 10, description: "The limit of search results per page")
arg(:limit, :integer,
default_value: 10,
description: "The limit of search results per page"
)
arg(:type, :address_search_type, description: "Filter by type of results")
middleware(Rajska.QueryAuthorization, permit: :all)

View file

@ -96,7 +96,9 @@ defmodule Mobilizon.GraphQL.Schema.Discussions.CommentType do
arg(:in_reply_to_comment_id, :id, description: "The comment ID this one replies to")
arg(:language, :string, description: "The comment language", default_value: "und")
arg(:is_announcement, :boolean, description: "Should this comment be announced to everyone?")
arg(:is_announcement, :boolean,
description: "Should this comment be announced to everyone?"
)
middleware(Rajska.QueryAuthorization,
permit: :user,
@ -114,7 +116,9 @@ defmodule Mobilizon.GraphQL.Schema.Discussions.CommentType do
arg(:comment_id, non_null(:id), description: "The comment ID")
arg(:language, :string, description: "The comment language", default_value: "und")
arg(:is_announcement, :boolean, description: "Should this comment be announced to everyone?")
arg(:is_announcement, :boolean,
description: "Should this comment be announced to everyone?"
)
middleware(Rajska.QueryAuthorization,
permit: :user,

View file

@ -230,7 +230,9 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "Whether or not to allow anonymous participation (if the server allows it)"
)
field(:offers, list_of(:event_offer), description: "The list of offers to show for this event")
field(:offers, list_of(:event_offer),
description: "The list of offers to show for this event"
)
field(:participation_conditions, list_of(:event_participation_condition),
description: "The list of participation conditions to accept to join this event"
@ -414,7 +416,9 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "The event's organizer ID (as a person)"
)
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
arg(:attributed_to_id, :id,
description: "Who the event is attributed to ID (often a group)"
)
arg(:category, :event_category,
default_value: "MEETING",
@ -476,7 +480,9 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
arg(:phone_address, :string, description: "Phone address for the event")
arg(:organizer_actor_id, :id, description: "The event's organizer ID (as a person)")
arg(:attributed_to_id, :id, description: "Who the event is attributed to ID (often a group)")
arg(:attributed_to_id, :id,
description: "Who the event is attributed to ID (often a group)"
)
arg(:category, :event_category, description: "The event's category")
arg(:physical_address, :address_input, description: "The event's physical address")

View file

@ -25,7 +25,10 @@ defmodule Mobilizon.GraphQL.Schema.ResourceType do
field(:type, :string, description: "The resource's type (if it's a folder)")
field(:path, :string, description: "The resource's path")
field(:parent, :resource, description: "The resource's parent", resolve: dataloader(Resources))
field(:parent, :resource,
description: "The resource's parent",
resolve: dataloader(Resources)
)
field :children, :paginated_resource_list do
description("Children resources in folder")

View file

@ -73,7 +73,9 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
description: "The list of participations this user has",
meta: [private: true, rule: :"read:user:participations"]
) do
arg(:after_datetime, :datetime, description: "Filter participations by event start datetime")
arg(:after_datetime, :datetime,
description: "Filter participations by event start datetime"
)
arg(:before_datetime, :datetime, description: "Filter participations by event end datetime")
@ -148,7 +150,9 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
field(:last_sign_in_at, :datetime, description: "When the user previously signed-in")
field(:last_sign_in_ip, :string, description: "The IP adress the user previously sign-in with")
field(:last_sign_in_ip, :string,
description: "The IP adress the user previously sign-in with"
)
field(:current_sign_in_at, :datetime, description: "When the user currenlty signed-in")

View file

@ -1310,7 +1310,9 @@ defmodule Mobilizon.Actors do
def schedule_key_rotation(%Actor{id: actor_id} = actor, delay) do
Cachex.put(:actor_key_rotation, actor_id, true)
Workers.Background.enqueue("actor_key_rotation", %{"actor_id" => actor.id}, schedule_in: delay)
Workers.Background.enqueue("actor_key_rotation", %{"actor_id" => actor.id},
schedule_in: delay
)
:ok
end

View file

@ -78,6 +78,11 @@ defmodule Mobilizon.Admin do
defp stringify_struct(struct), do: struct
@spec get_all_admin_settings :: list(Setting.t())
def get_all_admin_settings do
Repo.all(Setting)
end
@spec get_admin_setting_value(String.t(), String.t(), String.t() | nil) ::
String.t() | boolean() | nil | map() | list()
def get_admin_setting_value(group, name, fallback \\ nil)

View file

@ -4,6 +4,7 @@ defmodule Mobilizon.Config do
"""
alias Mobilizon.Actors
alias Mobilizon.Admin.Setting
alias Mobilizon.Service.GitStatus
require Logger
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
@ -28,10 +29,67 @@ defmodule Mobilizon.Config do
@spec instance_config :: mobilizon_config
def instance_config, do: Application.get_env(:mobilizon, :instance)
@spec db_instance_config :: list(Setting.t())
def db_instance_config, do: Mobilizon.Admin.get_all_admin_settings()
@spec config_cache :: map()
def config_cache do
case Cachex.fetch(:config, :all_db_config, fn _key ->
value =
Enum.reduce(
Mobilizon.Admin.get_all_admin_settings(),
%{},
&arrange_values/2
)
{:commit, value}
end) do
{status, value} when status in [:ok, :commit] -> value
_err -> %{}
end
end
@spec arrange_values(Setting.t(), map()) :: map()
defp arrange_values(setting, acc) do
{_, new_data} =
Map.get_and_update(acc, setting.group, fn current_value ->
new_value = current_value || %{}
{current_value, Map.put(new_value, setting.name, process_value(setting.value))}
end)
new_data
end
@spec process_value(String.t() | nil) :: any()
defp process_value(nil), do: nil
defp process_value(""), do: nil
defp process_value(value) do
case Jason.decode(value) do
{:ok, val} ->
val
{:error, _} ->
case value do
"true" -> true
"false" -> false
value -> value
end
end
end
@spec config_cached_value(String.t(), String.t(), String.t()) :: any()
def config_cached_value(group, name, fallback \\ nil) do
config_cache()
|> Map.get(group, %{})
|> Map.get(name, fallback)
end
@spec instance_name :: String.t()
def instance_name,
do:
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"instance_name",
instance_config()[:name]
@ -40,7 +98,7 @@ defmodule Mobilizon.Config do
@spec instance_description :: String.t()
def instance_description,
do:
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"instance_description",
instance_config()[:description]
@ -49,37 +107,37 @@ defmodule Mobilizon.Config do
@spec instance_long_description :: String.t()
def instance_long_description,
do:
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"instance_long_description"
)
@spec instance_slogan :: String.t() | nil
def instance_slogan, do: Mobilizon.Admin.get_admin_setting_value("instance", "instance_slogan")
def instance_slogan, do: config_cached_value("instance", "instance_slogan")
@spec contact :: String.t() | nil
def contact do
Mobilizon.Admin.get_admin_setting_value("instance", "contact")
config_cached_value("instance", "contact")
end
@spec instance_terms(String.t()) :: String.t()
def instance_terms(locale \\ "en") do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_terms", generate_terms(locale))
config_cached_value("instance", "instance_terms", generate_terms(locale))
end
@spec instance_terms_type :: String.t()
def instance_terms_type do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_terms_type", "DEFAULT")
config_cached_value("instance", "instance_terms_type", "DEFAULT")
end
@spec instance_terms_url :: String.t() | nil
def instance_terms_url do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_terms_url")
config_cached_value("instance", "instance_terms_url")
end
@spec instance_privacy(String.t()) :: String.t()
def instance_privacy(locale \\ "en") do
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"instance_privacy_policy",
generate_privacy(locale)
@ -88,17 +146,17 @@ defmodule Mobilizon.Config do
@spec instance_privacy_type :: String.t()
def instance_privacy_type do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_privacy_policy_type", "DEFAULT")
config_cached_value("instance", "instance_privacy_policy_type", "DEFAULT")
end
@spec instance_privacy_url :: String.t()
def instance_privacy_url do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_privacy_policy_url")
config_cached_value("instance", "instance_privacy_policy_url")
end
@spec instance_rules :: String.t()
def instance_rules do
Mobilizon.Admin.get_admin_setting_value("instance", "instance_rules")
config_cached_value("instance", "instance_rules")
end
@spec instance_version :: String.t()
@ -113,7 +171,7 @@ defmodule Mobilizon.Config do
def instance_registrations_open?,
do:
to_boolean(
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"registrations_open",
instance_config()[:registrations_open]
@ -123,7 +181,7 @@ defmodule Mobilizon.Config do
@spec instance_languages :: list(String.t())
def instance_languages,
do:
Mobilizon.Admin.get_admin_setting_value(
config_cached_value(
"instance",
"instance_languages",
instance_config()[:languages]
@ -322,8 +380,6 @@ defmodule Mobilizon.Config do
@spec anonymous_actor_id :: integer
def anonymous_actor_id, do: get_cached_value(:anonymous_actor_id)
@spec admin_settings :: map
def admin_settings, do: get_cached_value(:admin_config)
@spec get(keys :: module | atom | [module | atom]) :: any
def get(key), do: get(key, nil)
@ -399,8 +455,11 @@ defmodule Mobilizon.Config do
end
end
defp create_cache(:admin_config) do
data = %{
defp create_cache(_), do: {:error, :cache_key_not_handled}
@spec admin_settings :: map()
def admin_settings do
%{
instance_description: instance_description(),
instance_long_description: instance_long_description(),
instance_name: instance_name(),
@ -416,8 +475,6 @@ defmodule Mobilizon.Config do
instance_rules: instance_rules(),
instance_languages: instance_languages()
}
{:ok, data}
end
@spec clear_config_cache :: {:ok | :error, integer}

View file

@ -108,7 +108,7 @@ defmodule Mobilizon.Events.Participant do
end
# No lookalike symbols
@symbols '6789BCDFGHJKLMNPQRTW'
@symbols ~c"6789BCDFGHJKLMNPQRTW"
@symbol_count Enum.count(@symbols) - 1
@code_length 6

View file

@ -183,15 +183,15 @@ defmodule Mobilizon.Service.Auth.LDAPAuthenticator do
@spec search_filter(String.t(), boolean()) :: any()
defp search_filter(email, false) do
:eldap.equalityMatch('mail', to_charlist(email))
:eldap.equalityMatch(~c"mail", to_charlist(email))
end
# If we need to filter for group memberships as well
@spec search_filter(String.t(), String.t()) :: any()
defp search_filter(email, group) when is_binary(group) do
:eldap.and([
:eldap.equalityMatch('mail', to_charlist(email)),
:eldap.equalityMatch('memberOf', to_charlist(group))
:eldap.equalityMatch(~c"mail", to_charlist(email)),
:eldap.equalityMatch(~c"memberOf", to_charlist(group))
])
end

View file

@ -8,6 +8,7 @@ defmodule Mobilizon.Service.Export.Participants.CSV do
alias Mobilizon.Storage.Repo
alias Mobilizon.Web.Gettext
import Mobilizon.Web.Gettext, only: [gettext: 2]
require Logger
import Mobilizon.Service.Export.Participants.Common,
only: [
@ -30,9 +31,18 @@ defmodule Mobilizon.Service.Export.Participants.CSV do
def export(%Event{} = event, options \\ []) do
if ready?() do
filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.csv"
full_path = Path.join([export_path(@extension), filename])
folder = export_path(@extension)
folder_creation_result = File.mkdir_p(folder)
file = File.open!(full_path, [:write, :utf8])
if folder_creation_result != :ok do
Logger.warning(
"Unable to create folder at #{folder}, error result #{inspect(folder_creation_result)}"
)
end
full_path = Path.join([folder, filename])
file = File.open!(full_path, [:write, :exclusive, :utf8])
case Repo.transaction(
fn ->

View file

@ -7,7 +7,10 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Discussions.Comment do
@spec build_tags(Comment.t(), String.t()) :: list(Phoenix.HTML.safe())
def build_tags(%Comment{deleted_at: nil} = comment, _locale) do
[
Tag.tag(:meta, property: "og:title", content: escape_text(Actor.display_name(comment.actor))),
Tag.tag(:meta,
property: "og:title",
content: escape_text(Actor.display_name(comment.actor))
),
Tag.tag(:meta, property: "og:url", content: comment.url),
Tag.tag(:meta, property: "og:description", content: comment.text),
Tag.tag(:meta, property: "og:type", content: "website"),

14
mix.exs
View file

@ -7,7 +7,7 @@ defmodule Mobilizon.Mixfile do
[
app: :mobilizon,
version: @version,
elixir: "~> 1.12",
elixir: "~> 1.13",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),
xref: [exclude: [:eldap]],
@ -80,10 +80,18 @@ defmodule Mobilizon.Mixfile do
def application do
[
mod: {Mobilizon, []},
extra_applications: [:logger, :runtime_tools, :guardian, :geolix, :crypto, :cachex]
extra_applications: extra_applications(Mix.env())
]
end
defp extra_applications(:test) do
extra_applications(:prod) ++ [:inets, :ssl]
end
defp extra_applications(_env) do
[:logger, :runtime_tools, :guardian, :geolix, :crypto, :cachex]
end
def copy_files(%{path: target_path} = release) do
File.cp_r!("./rel/overlays", target_path)
release
@ -215,7 +223,7 @@ defmodule Mobilizon.Mixfile do
# Dev and test dependencies
{:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]},
{:ex_machina, "~> 2.3", only: [:dev, :test]},
{:excoveralls, "~> 0.16.0", only: :test},
{:excoveralls, "~> 0.17.0", only: :test},
{:ex_doc, "~> 0.25", only: [:dev, :test], runtime: false},
{:mix_test_watch, "~> 1.0", only: :dev, runtime: false},
{:ex_unit_notifier, "~> 1.0", only: :test},

View file

@ -28,7 +28,7 @@
"earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"},
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "3.0.0", "37fbc2f07e6691136afff246f2cf5b159ad395b665a55d06db918975fd2397db", [:mix], [{:ecto, ">= 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.3.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "8ec252c7cf85f13132062f56a484d6a0ef1f981f7be9ce4ad7e9546dd8c0cc0f"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "3.1.0", "ddf26e814baf3c32c6aebfed56a637f10a097db83f65d71e6f2d1e7faf2e9e51", [:mix], [{:ecto, ">= 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugify, "~> 1.3", [hex: :slugify, repo: "hexpm", optional: false]}], "hexpm", "b6ddd614805263e24b5c169532c934440d0289181cce873061fca3a8e92fd9ff"},
"ecto_dev_logger": {:hex, :ecto_dev_logger, "0.9.0", "cb631469ac1940e97655d6fce85905b792ac9250ab18b19c664978b79f8dad59", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2e8bc98b4ae4fcc7108896eef7da5a109afad829f4fb2eb46d677fdc9101c2d5"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_shortuuid": {:hex, :ecto_shortuuid, "0.2.0", "57cae7b6016cc56a04457b4fc8f63957398dfd9023ff3e900eaf6805a40f8043", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:shortuuid, "~> 2.1 or ~> 3.0", [hex: :shortuuid, repo: "hexpm", optional: false]}], "hexpm", "b92e3b71e86be92f5a7ef6f3de170e7864454e630f7b01dd930414baf38efb65"},
@ -41,16 +41,16 @@
"ex_cldr": {:hex, :ex_cldr, "2.37.2", "c45041534ec60af367c4c1af02a608576118044fe3c441c782fd424061d6b517", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "c8467b1d5080716ace6621703b6656cb2f9545572a54b341da900791a0cf92ba"},
"ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.22.1", "3e5150f1fe7698e0fa118aeedcca1b5920d0a552bc40c81cf65ca9b0a4ea4cc3", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.16", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e7408cd9e8318b2ef93b76728e84484ddc3ea6d7c894fbc811c54122a7140169"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.0", "aadd34e91cfac7ef6b03fe8f47f8c6fa8c5daf3f89b5d9fee64ec545ded839cf", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0521316396c66877a2d636219767560bb2397c583341fcb154ecf9f3000e6ff8"},
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.13.3", "bd01c75f017b3a024d0d4c189f2ee0573c15023e98ae16759228a7b57f9414bc", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr, "~> 2.36", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_calendars, "~> 1.18", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.28", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "f5b2216189bd9118bb2e5c1abd48f95f48b2eac954fe0e53370806d23b1641ac"},
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.14.0", "5f0d7a9f5e21ffd33016c08e24e2f91e3f80c9c20ee881358c0ea89e44463cc5", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.22", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:tz, "~> 0.26", [hex: :tz, repo: "hexpm", optional: true]}], "hexpm", "f85a8b00546f6aecc2df7a97f15b9de66662d81578653128699c839f7a40bf94"},
"ex_cldr_languages": {:hex, :ex_cldr_languages, "0.3.3", "9787002803552b15a7ade19496c9e46fc921baca992ea80d0394e11fe3acea45", [:mix], [{:ex_cldr, "~> 2.25", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "22fb1fef72b7b4b4872d243b34e7b83734247a78ad87377986bf719089cc447a"},
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.31.3", "6ec8b18c395c0e8788d46da806f8f2abcbe4b0d809226d2a91363e9ccd85f2f5", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "b519de08ecc4a6402038f3aa75e8654f78ebd6fa714b7e585531504e648588fd"},
"ex_cldr_plugs": {:hex, :ex_cldr_plugs, "1.3.0", "72a2064cb36c390dd0b212e8a172f643d455c8d362ee9c4bda29a96b42204df6", [:mix], [{:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "699a98543ea14a7c849fae768041c40f49aa611aa55866025d227796e4858bff"},
"ex_doc": {:hex, :ex_doc, "0.30.3", "bfca4d340e3b95f2eb26e72e4890da83e2b3a5c5b0e52607333bf5017284b063", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "fbc8702046c1d25edf79de376297e608ac78cdc3a29f075484773ad1718918b6"},
"ex_doc": {:hex, :ex_doc, "0.30.5", "aa6da96a5c23389d7dc7c381eba862710e108cee9cfdc629b7ec021313900e9e", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "88a1e115dcb91cefeef7e22df4a6ebbe4634fbf98b38adcbc25c9607d6d9d8e6"},
"ex_ical": {:hex, :ex_ical, "0.2.0", "4b928b554614704016cc0c9ee226eb854da9327a1cc460457621ceacb1ac29a6", [:mix], [{:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "db76473b2ae0259e6633c6c479a5a4d8603f09497f55c88f9ef4d53d2b75befb"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_optimizer": {:hex, :ex_optimizer, "0.1.1", "62da37e206fc2233ff7a4e54e40eae365c40f96c81992fcd15b782eb25169b80", [:mix], [{:file_info, "~> 0.0.4", [hex: :file_info, repo: "hexpm", optional: false]}], "hexpm", "e6f5c059bcd58b66be2f6f257fdc4f69b74b0fa5c9ddd669486af012e4b52286"},
"ex_unit_notifier": {:hex, :ex_unit_notifier, "1.3.0", "1d82aa6d2fb44e6f0f219142661a46e13dcba833e150e1395190d2e0fb721990", [:mix], [], "hexpm", "55fffd6062e8d962fc44e8b06fa30a87dc7251ee2a69f520781a3bb29858c365"},
"excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"},
"excoveralls": {:hex, :excoveralls, "0.17.0", "279f124dba347903bb654bc40745c493ae265d45040001b4899ea1edf88078c7", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "08b638d114387a888f9cb8d65f2a0021ec04c3e447b793efa7c1e734aba93004"},
"exgravatar": {:hex, :exgravatar, "2.0.3", "2349709832ee535f826f48db98cddd294ae62b01acb44d539a16419bd8ebc3e5", [:mix], [], "hexpm", "aca18ff9bd8991d3be3e5446d3bdefc051be084c1ffc9ab2d43b3e65339300e1"},
"exkismet": {:git, "https://github.com/tcitworld/exkismet.git", "8b5485fde00fafbde20f315bec387a77f7358334", []},
"expo": {:hex, :expo, "0.1.0", "d4e932bdad052c374118e312e35280f1919ac13881cb3ac07a209a54d0c81dd8", [:mix], [], "hexpm", "c22c536021c56de058aaeedeabb4744eb5d48137bacf8c29f04d25b6c6bbbf45"},
@ -103,12 +103,12 @@
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"},
"oauther": {:hex, :oauther, "1.3.0", "82b399607f0ca9d01c640438b34d74ebd9e4acd716508f868e864537ecdb1f76", [:mix], [], "hexpm", "78eb888ea875c72ca27b0864a6f550bc6ee84f2eeca37b093d3d833fbcaec04e"},
"oban": {:hex, :oban, "2.15.2", "8f934a49db39163633965139c8846d8e24c2beb4180f34a005c2c7c3f69a6aa2", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0f4a579ea48fc7489e0d84facf8b01566e142bdc6542d7dabce32c10e664f1e9"},
"oban": {:hex, :oban, "2.15.4", "d49ab4ffb7153010e32f80fe9e56f592706238149ec579eb50f8a4e41d218856", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fce611fdfffb13e9148df883116e5201adf1e731eb302cc88cde0588510079c"},
"paasaa": {:hex, :paasaa, "0.6.0", "07c8ed81010caa25db351d474f0c053072c809821c60f9646f7b1547bec52f6d", [:mix], [], "hexpm", "732ddfc21bac0831edb26aec468af3ec2b8997d74f6209810b1cc53199c29f2e"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"phoenix": {:hex, :phoenix, "1.7.7", "4cc501d4d823015007ba3cdd9c41ecaaf2ffb619d6fb283199fa8ddba89191e0", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8966e15c395e5e37591b6ed0bd2ae7f48e961f0f60ac4c733f9566b519453085"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"},
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
"phoenix_html": {:hex, :phoenix_html, "3.3.2", "d6ce982c6d8247d2fc0defe625255c721fb8d5f1942c5ac051f6177bffa5973f", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "44adaf8e667c1c20fb9d284b6b0fa8dc7946ce29e81ce621860aa7e96de9a11d"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.19.5", "6e730595e8e9b8c5da230a814e557768828fd8dfeeb90377d2d8dbb52d4ec00a", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b2eaa0dd3cfb9bd7fb949b88217df9f25aed915e986a28ad5c8a0d054e7ca9d3"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
@ -130,15 +130,16 @@
"sitemapper": {:hex, :sitemapper, "0.7.0", "4aee7930327a9a01b1c9b81d1d42f60c1a295e9f420108eb2d130c317415abd7", [:mix], [{:ex_aws_s3, "~> 2.0", [hex: :ex_aws_s3, repo: "hexpm", optional: true]}, {:xml_builder, "~> 2.1", [hex: :xml_builder, repo: "hexpm", optional: false]}], "hexpm", "60f7a684e5e9fe7f10ac5b69f48b0be2bcbba995afafcb3c143fc0c8ef1f223f"},
"sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},
"sobelow": {:hex, :sobelow, "0.12.2", "45f4d500e09f95fdb5a7b94c2838d6b26625828751d9f1127174055a78542cf5", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2f0b617dce551db651145662b84c8da4f158e7abe049a76daaaae2282df01c5d"},
"slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"},
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"struct_access": {:hex, :struct_access, "1.1.2", "a42e6ceedd9b9ea090ee94a6da089d56e16f374dbbc010c3eebdf8be17df286f", [:mix], [], "hexpm", "e4c411dcc0226081b95709909551fc92b8feb1a3476108348ea7e3f6c12e586a"},
"sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"},
"swoosh": {:hex, :swoosh, "1.11.4", "9b353f998cba3c5e101a0669559c2fb2757b5d9eb7db058bf08687d82e93e416", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d3390914022a456ae1604bfcb3431bd12509b2afe8c70296bae6c9dca4903d0f"},
"swoosh": {:hex, :swoosh, "1.11.5", "429dccde78e2f60c6339e96917efecebca9d1f254d2878a150f580d2f782260b", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21ee57dcd68d2f56d3bbe11e76d56d142b221bb12b6018c551cc68442b800040"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"tz_world": {:hex, :tz_world, "1.3.0", "a4d70486c7934b710f8b3b4374d62ebdd75e3d2b8914771ef6c62c3635a6088f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:geo, "~> 1.0 or ~> 2.0 or ~> 3.3", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "78b565aa0899b48ce34686319119dfdadff07a255ec43fd9ed6e7d60cc8d1390"},
"tz_world": {:hex, :tz_world, "1.3.1", "dedb8373fce594098909ff36d37f5e5e30e47cb40ef846d1dfc91eb39f7ebaaf", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:geo, "~> 1.0 or ~> 2.0 or ~> 3.3", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "901ed2b4a4430ecab3765244da4a19e6f19141867c2ab3753924919b87ed2224"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
"ueberauth_cas": {:hex, :ueberauth_cas, "2.3.1", "df45a1f2c5df8bc80191cbca4baeeed808d697702ec5ebe5bd5d5a264481752f", [:mix], [{:httpoison, "~> 1.8", [hex: :httpoison, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "5068ae2b9e217c2f05aa9a67483a6531e21ba0be9a6f6c8749bb7fd1599be321"},
@ -146,7 +147,7 @@
"ueberauth_facebook": {:hex, :ueberauth_facebook, "0.10.0", "0d607fbd1b7c6e0449981571027d869c2d156b8ad20c42e3672346678c05ccf1", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "bf8ce5d66b1c50da8abff77e8086c1b710bdde63f4acaef19a651ba43a9537a8"},
"ueberauth_github": {:hex, :ueberauth_github, "0.8.3", "1c478629b4c1dae446c68834b69194ad5cead3b6c67c913db6fdf64f37f0328f", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "ae0ab2879c32cfa51d7287a48219b262bfdab0b7ec6629f24160564247493cc6"},
"ueberauth_gitlab_strategy": {:hex, :ueberauth_gitlab_strategy, "0.4.0", "96605d304ebb87ce508eccbeb1f94da9ea1c9da20d8913771b6cf24a6cc6c633", [:mix], [{:oauth2, "~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "e86e2e794bb063c07c05a6b1301b73f2be3ba9308d8f47ecc4d510ef9226091e"},
"ueberauth_google": {:hex, :ueberauth_google, "0.10.2", "b85b3de6070e7bc71bbec3d4dbe2de805b004ae9c19efeb31531f9134ede4033", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "fcf987749db5e2d890240ce61223c61ee6ac1d638c3378bf1eeeb0e6332e5a12"},
"ueberauth_google": {:hex, :ueberauth_google, "0.10.3", "eb1d3973578105e884861facff641e6c03209d621532f988d071dd6d7a46f73b", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "2462ca9652acc936e0738691869d024e3e262f83ba9f6b4e874b961812290038"},
"ueberauth_keycloak_strategy": {:hex, :ueberauth_keycloak_strategy, "0.4.0", "51e975874564ef4a6eb0044b9f0c6a08be4ba6086e62e41d385e7dd52fe9568b", [:mix], [{:oauth2, "~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "c03027937bddcbd9ff499e457f9bb05f79018fa321abf79ebcfed2af0007211b"},
"ueberauth_twitter": {:hex, :ueberauth_twitter, "0.4.1", "92f88b1ad50322cdda719b439bb7f93b225dc0315723117bc25c782e627c8f33", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "83ca8ea3e1a3f976f1adbebfb323b9ebf53af453fbbf57d0486801a303b16065"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
@ -154,7 +155,7 @@
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
"vite_phx": {:hex, :vite_phx, "0.3.1", "0f7d8cd98018547a7d97122552fff3e2d70df2820bc70e8d4f31156dcb60f23a", [:mix], [{:jason, ">= 0.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, ">= 0.0.0", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "08b1726094a131490ff0a2c7764c4cdd4b5cdf8ba9762638a5dd4bcd9e5fc936"},
"web_push_encryption": {:git, "https://github.com/danhper/elixir-web-push-encryption.git", "70f00d06cbd88c9ac382e0ad2539e54448e9d8da", []},
"websock": {:hex, :websock, "0.5.2", "b3c08511d8d79ed2c2f589ff430bd1fe799bb389686dafce86d28801783d8351", [:mix], [], "hexpm", "925f5de22fca6813dfa980fb62fd542ec43a2d1a1f83d2caec907483fe66ff05"},
"websock_adapter": {:hex, :websock_adapter, "0.5.3", "4908718e42e4a548fc20e00e70848620a92f11f7a6add8cf0886c4232267498d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "cbe5b814c1f86b6ea002b52dd99f345aeecf1a1a6964e209d208fb404d930d3d"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.4", "7af8408e7ed9d56578539594d1ee7d8461e2dd5c3f57b0f2a5352d610ddde757", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d2c238c79c52cbe223fcdae22ca0bb5007a735b9e933870e241fce66afb4f4ab"},
"xml_builder": {:hex, :xml_builder, "2.2.0", "cc5f1eeefcfcde6e90a9b77fb6c490a20bc1b856a7010ce6396f6da9719cbbab", [:mix], [], "hexpm", "9d66d52fb917565d358166a4314078d39ef04d552904de96f8e73f68f64a62c9"},
}

View file

@ -20,7 +20,9 @@ defmodule Mobilizon.Repo.Migrations.CreateTodos do
add(:creator_id, references(:actors, on_delete: :delete_all), null: false)
add(:assigned_to_id, references(:actors, on_delete: :nilify_all))
add(:todo_list_id, references(:todo_lists, on_delete: :delete_all, type: :uuid), null: false)
add(:todo_list_id, references(:todo_lists, on_delete: :delete_all, type: :uuid),
null: false
)
timestamps()
end

View file

@ -34,7 +34,7 @@ defmodule Mobilizon.Federation.ActivityPubTest do
date: Signature.generate_date_header()
})
assert signature =~ "headers=\"(request-target) content-length date digest host\""
assert signature =~ "headers=\"date host digest content-length (request-target)\""
end
end

View file

@ -213,7 +213,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.CommentsTest do
{:ok, %Tesla.Env{status: 404, body: "Not found"}}
end)
assert capture_log([level: :warn], fn ->
assert capture_log([level: :warning], fn ->
{:ok, _returned_activity, _entity} = Transmogrifier.handle_incoming(data)
end) =~ "[warning] Parent object is something we don't handle"
end

View file

@ -84,7 +84,11 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.JoinTest do
insert(:member, actor: actor_member_2, parent: group, role: :moderator)
%Event{url: event_url} =
insert(:event, organizer_actor: organizer, join_options: :restricted, attributed_to: group)
insert(:event,
organizer_actor: organizer,
join_options: :restricted,
attributed_to: group
)
join_data =
File.read!("test/fixtures/mobilizon-join-activity.json")
@ -128,7 +132,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.JoinTest do
assert reject_activity.data["id"] =~ "/reject/join/"
# We don't accept already rejected Reject activities
assert capture_log([level: :warn], fn ->
assert capture_log([level: :warning], fn ->
assert :error == Transmogrifier.handle_incoming(reject_data)
end) =~
"Tried to handle an Reject activity on a Join activity with a event object but the participant is already rejected"

View file

@ -66,7 +66,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
|> Map.put("actor", relay_actor_url)
|> Map.put("object", object)
assert capture_log([level: :warn], fn ->
assert capture_log([level: :warning], fn ->
:error = Transmogrifier.handle_incoming(update_data)
end) =~ "[warning] Activity tried to update an actor that's local or not a group"

View file

@ -62,8 +62,8 @@ defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do
wholeSubtree: fn -> :ok end,
search: fn _connection, _options ->
{:ok,
{:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], [],
[]}}
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
[], []}}
end,
close: fn _connection ->
send(self(), :close_connection)
@ -111,8 +111,8 @@ defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do
wholeSubtree: fn -> :ok end,
search: fn _connection, _options ->
{:ok,
{:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], [],
[]}}
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
[], []}}
end,
close: fn _connection ->
send(self(), :close_connection)
@ -149,7 +149,9 @@ defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do
with_mocks [
{:eldap, [],
[
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:error, 'connect failed'} end,
open: fn [^host], [{:port, ^port}, {:ssl, false} | _] ->
{:error, ~c"connect failed"}
end,
simple_bind: fn _connection, _dn, password ->
case password do
^admin_password -> :ok
@ -160,7 +162,8 @@ defmodule Mobilizon.Service.Auth.LDAPAuthenticatorTest do
wholeSubtree: fn -> :ok end,
search: fn _connection, _options ->
{:ok,
{:eldap_search_result, [{:eldap_entry, '', [{'cn', [to_charlist("MyUser")]}]}], []}}
{:eldap_search_result, [{:eldap_entry, ~c"", [{~c"cn", [to_charlist("MyUser")]}]}],
[]}}
end,
close: fn _connection ->
send(self(), :close_connection)

View file

@ -15,7 +15,7 @@ defmodule Mobilizon.Service.Export.Participants.CSVTest do
assert CSV.ready?()
assert {:ok, path} = CSV.export(event)
assert content = File.read!("uploads/exports/csv/" <> path)
assert content = File.read!("test/uploads/exports/csv/" <> path)
assert content =~ "Participant name,Participant status,Participant message"
end
end

View file

@ -154,7 +154,11 @@ defmodule Mobilizon.Service.Notifications.SchedulerTest do
%User{id: user_id} = user = insert(:user, locale: "fr")
settings =
insert(:settings, user_id: user_id, notification_each_week: true, timezone: "Europe/Paris")
insert(:settings,
user_id: user_id,
notification_each_week: true,
timezone: "Europe/Paris"
)
user = Map.put(user, :settings, settings)
actor = insert(:actor, user: user)

View file

@ -166,7 +166,11 @@ defmodule Mobilizon.Service.Workers.NotificationTest do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_each_week: true, timezone: "Europe/Paris")
insert(:settings,
user_id: user_id,
notification_each_week: true,
timezone: "Europe/Paris"
)
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
@ -186,7 +190,11 @@ defmodule Mobilizon.Service.Workers.NotificationTest do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_each_week: true, timezone: "Europe/Paris")
insert(:settings,
user_id: user_id,
notification_each_week: true,
timezone: "Europe/Paris"
)
user = %User{user | settings: settings}
%Actor{} = actor = insert(:actor, user: user)
@ -210,7 +218,11 @@ defmodule Mobilizon.Service.Workers.NotificationTest do
%User{id: user_id} = user = insert(:user)
settings =
insert(:settings, user_id: user_id, notification_each_week: true, timezone: "Europe/Paris")
insert(:settings,
user_id: user_id,
notification_each_week: true,
timezone: "Europe/Paris"
)
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)
@ -229,7 +241,11 @@ defmodule Mobilizon.Service.Workers.NotificationTest do
%User{id: user_id} = user = insert(:user, email: @email)
settings =
insert(:settings, user_id: user_id, notification_each_week: true, timezone: "Europe/Paris")
insert(:settings,
user_id: user_id,
notification_each_week: true,
timezone: "Europe/Paris"
)
user = Map.put(user, :settings, settings)
%Actor{} = actor = insert(:actor, user: user)

View file

@ -23,7 +23,7 @@ defmodule Mobilizon.Web.WebFingerControllerTest do
conn = get(conn, "/.well-known/host-meta")
assert response(conn, 200) ==
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\" xmlns:hm=\"http://host-meta.net/ns/1.0\"><hm:Host>mobilizon.test</hm:Host><Link rel=\"lrdd\" template=\"#{Endpoint.url()}/.well-known/webfinger?resource={uri}\" type=\"application/jrd+json\" /></XRD>"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\" xmlns:hm=\"http://host-meta.net/ns/1.0\"><hm:Host>mobilizon.test</hm:Host><Link type=\"application/jrd+json\" template=\"#{Endpoint.url()}/.well-known/webfinger?resource={uri}\" rel=\"lrdd\" /></XRD>"
assert {"content-type", "application/xrd+xml; charset=utf-8"} in conn.resp_headers
end