use Mix.Config
# General application configuration
-config :pleroma,
- ecto_repos: [Pleroma.Repo]
+config :pleroma, ecto_repos: [Pleroma.Repo]
-config :pleroma, Pleroma.Repo,
- types: Pleroma.PostgresTypes
+config :pleroma, Pleroma.Repo, types: Pleroma.PostgresTypes
-config :pleroma, Pleroma.Upload,
- uploads: "uploads"
+config :pleroma, Pleroma.Upload, uploads: "uploads"
# Configures the endpoint
config :pleroma, Pleroma.Web.Endpoint,
protocol: "https",
secret_key_base: "aK4Abxf29xU9TTDKre9coZPUgevcVCFQJe/5xP/7Lt4BEif6idBIbjupVbOrbKxl",
render_errors: [view: Pleroma.Web.ErrorView, accepts: ~w(json)],
- pubsub: [name: Pleroma.PubSub,
- adapter: Phoenix.PubSub.PG2]
+ pubsub: [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]
# Configures Elixir's Logger
config :logger, :console,
config :pleroma, :ostatus, Pleroma.Web.OStatus
config :pleroma, :httpoison, Pleroma.HTTP
-version = with {version, 0} <- System.cmd("git", ["rev-parse", "HEAD"]) do
- "Pleroma #{Mix.Project.config[:version]} #{String.trim(version)}"
- else
- _ -> "Pleroma #{Mix.Project.config[:version]} dev"
- end
+version =
+ with {version, 0} <- System.cmd("git", ["rev-parse", "HEAD"]) do
+ "Pleroma #{Mix.Project.config()[:version]} #{String.trim(version)}"
+ else
+ _ -> "Pleroma #{Mix.Project.config()[:version]} dev"
+ end
# Configures http settings, upstream proxy etc.
-config :pleroma, :http,
- proxy_url: nil
+config :pleroma, :http, proxy_url: nil
config :pleroma, :instance,
version: version,
config :pleroma, :media_proxy,
enabled: false,
redirect_on_failure: true
- #base_url: "https://cache.pleroma.social"
-config :pleroma, :chat,
- enabled: true
+# base_url: "https://cache.pleroma.social"
+
+config :pleroma, :chat, enabled: true
config :ecto, json_library: Jason
-config :phoenix, :format_encoders,
- json: Jason
+config :phoenix, :format_encoders, json: Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
-import_config "#{Mix.env}.exs"
+import_config "#{Mix.env()}.exs"
# watchers to your application. For example, we use it
# with brunch.io to recompile .js and .css sources.
config :pleroma, Pleroma.Web.Endpoint,
- http: [port: 4000, protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]],
+ http: [
+ port: 4000,
+ protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]
+ ],
protocol: "http",
debug_errors: true,
code_reloader: true,
try do
import_config "dev.secret.exs"
rescue
- _-> IO.puts("!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs")
+ _ ->
+ IO.puts(
+ "!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs"
+ )
end
# Print only warnings and errors during test
config :logger, level: :warn
-config :pleroma, Pleroma.Upload,
- uploads: "test/uploads"
+config :pleroma, Pleroma.Upload, uploads: "test/uploads"
# Configure your database
config :pleroma, Pleroma.Repo,
hostname: System.get_env("DB_HOST") || "localhost",
pool: Ecto.Adapters.SQL.Sandbox
-
# Reduce hash rounds for testing
config :comeonin, :pbkdf2_rounds, 1
-Postgrex.Types.define(Pleroma.PostgresTypes, [] ++ Ecto.Adapters.Postgres.extensions(), json: Jason)
+Postgrex.Types.define(
+ Pleroma.PostgresTypes,
+ [] ++ Ecto.Adapters.Postgres.extensions(),
+ json: Jason
+)
def run([]) do
Mix.Task.run("app.start")
- q = from u in User,
- where: fragment("? @> ?", u.info, ^%{"ap_enabled" => true}),
- where: u.local == false
+ q =
+ from(
+ u in User,
+ where: fragment("? @> ?", u.info, ^%{"ap_enabled" => true}),
+ where: u.local == false
+ )
+
users = Repo.all(q)
- Enum.each(users, fn(user) ->
+ Enum.each(users, fn user ->
try do
IO.puts("Fetching #{user.nickname}")
Pleroma.Web.ActivityPub.Transmogrifier.upgrade_user_from_ap_id(user.ap_id, false)
def run(_) do
IO.puts("Answer a few questions to generate a new config\n")
IO.puts("--- THIS WILL OVERWRITE YOUR config/generated_config.exs! ---\n")
- domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim
- name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim
- email = IO.gets("What's your admin email address: ") |> String.trim
- mediaproxy = IO.gets("Do you want to activate the mediaproxy? (y/N): ")
- |> String.trim()
- |> String.downcase()
- |> String.starts_with?("y")
- proxy_url = if mediaproxy do
- IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ") |> String.trim
- else
- "https://cache.example.com"
- end
- secret = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
- dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64 |> binary_part(0, 64)
-
- resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", [dbpass: dbpass])
- result = EEx.eval_file("lib/mix/tasks/sample_config.eex", [domain: domain, email: email, name: name, secret: secret, mediaproxy: mediaproxy, proxy_url: proxy_url, dbpass: dbpass])
-
- IO.puts("\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs")
+ domain = IO.gets("What is your domain name? (e.g. pleroma.soykaf.com): ") |> String.trim()
+ name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim()
+ email = IO.gets("What's your admin email address: ") |> String.trim()
+
+ mediaproxy =
+ IO.gets("Do you want to activate the mediaproxy? (y/N): ")
+ |> String.trim()
+ |> String.downcase()
+ |> String.starts_with?("y")
+
+ proxy_url =
+ if mediaproxy do
+ IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ")
+ |> String.trim()
+ else
+ "https://cache.example.com"
+ end
+
+ secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
+ dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
+
+ resultSql = EEx.eval_file("lib/mix/tasks/sample_psql.eex", dbpass: dbpass)
+
+ result =
+ EEx.eval_file(
+ "lib/mix/tasks/sample_config.eex",
+ domain: domain,
+ email: email,
+ name: name,
+ secret: secret,
+ mediaproxy: mediaproxy,
+ proxy_url: proxy_url,
+ dbpass: dbpass
+ )
+
+ IO.puts(
+ "\nWriting config to config/generated_config.exs.\n\nCheck it and configure your database, then copy it to either config/dev.secret.exs or config/prod.secret.exs"
+ )
+
File.write("config/generated_config.exs", result)
- IO.puts("\nWriting setup_db.psql, please run it as postgre superuser, i.e.: sudo su postgres -c 'psql -f config/setup_db.psql'")
+
+ IO.puts(
+ "\nWriting setup_db.psql, please run it as postgre superuser, i.e.: sudo su postgres -c 'psql -f config/setup_db.psql'"
+ )
+
File.write("config/setup_db.psql", resultSql)
end
end
with %User{local: true} = user <- User.get_by_nickname(nickname),
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
- IO.puts "Generated password reset token for #{user.nickname}"
- IO.puts "Url: #{Pleroma.Web.Router.Helpers.util_url(Pleroma.Web.Endpoint, :show_password_reset, token.token)}"
+ IO.puts("Generated password reset token for #{user.nickname}")
+
+ IO.puts(
+ "Url: #{
+ Pleroma.Web.Router.Helpers.util_url(
+ Pleroma.Web.Endpoint,
+ :show_password_reset,
+ token.token
+ )
+ }"
+ )
else
_ ->
- IO.puts "No local user #{nickname}"
+ IO.puts("No local user #{nickname}")
end
end
end
def run([nickname | rest]) do
ensure_started(Repo, [])
- moderator = case rest do
- [moderator] -> moderator == "true"
- _ -> true
- end
+ moderator =
+ case rest do
+ [moderator] -> moderator == "true"
+ _ -> true
+ end
with %User{local: true} = user <- User.get_by_nickname(nickname) do
- info = user.info
- |> Map.put("is_moderator", !!moderator)
+ info =
+ user.info
+ |> Map.put("is_moderator", !!moderator)
+
cng = User.info_changeset(user, %{info: info})
user = Repo.update!(cng)
- IO.puts "Moderator status of #{nickname}: #{user.info["is_moderator"]}"
+ IO.puts("Moderator status of #{nickname}: #{user.info["is_moderator"]}")
else
_ ->
- IO.puts "No local user #{nickname}"
+ IO.puts("No local user #{nickname}")
end
end
end
alias Pleroma.{User, PasswordResetToken, Repo}
schema "password_reset_tokens" do
- belongs_to :user, User
- field :token, :string
- field :used, :boolean, default: false
+ belongs_to(:user, User)
+ field(:token, :string)
+ field(:used, :boolean, default: false)
timestamps()
end
def create_token(%User{} = user) do
- token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+ token = :crypto.strong_rand_bytes(32) |> Base.url_encode64()
token = %PasswordResetToken{
user_id: user.id,
import Ecto.Query
schema "activities" do
- field :data, :map
- field :local, :boolean, default: true
- field :actor, :string
- field :recipients, {:array, :string}
- has_many :notifications, Notification, on_delete: :delete_all
+ field(:data, :map)
+ field(:local, :boolean, default: true)
+ field(:actor, :string)
+ field(:recipients, {:array, :string})
+ has_many(:notifications, Notification, on_delete: :delete_all)
timestamps()
end
def get_by_ap_id(ap_id) do
- Repo.one(from activity in Activity,
- where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)))
+ Repo.one(
+ from(
+ activity in Activity,
+ where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id))
+ )
+ )
end
# TODO:
# Go through these and fix them everywhere.
# Wrong name, only returns create activities
def all_by_object_ap_id_q(ap_id) do
- from activity in Activity,
- where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^to_string(ap_id)),
+ from(
+ activity in Activity,
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
+ activity.data,
+ ^to_string(ap_id)
+ ),
where: fragment("(?)->>'type' = 'Create'", activity.data)
+ )
end
# Wrong name, returns all.
def all_non_create_by_object_ap_id_q(ap_id) do
- from activity in Activity,
- where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^to_string(ap_id))
+ from(
+ activity in Activity,
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
+ activity.data,
+ ^to_string(ap_id)
+ )
+ )
end
# Wrong name plz fix thx
end
def create_activity_by_object_id_query(ap_ids) do
- from activity in Activity,
- where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", activity.data, activity.data, ^ap_ids),
+ from(
+ activity in Activity,
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)",
+ activity.data,
+ activity.data,
+ ^ap_ids
+ ),
where: fragment("(?)->>'type' = 'Create'", activity.data)
+ )
end
def get_create_activity_by_object_ap_id(ap_id) do
create_activity_by_object_id_query([ap_id])
- |> Repo.one
+ |> Repo.one()
end
end
import Supervisor.Spec
# Define workers and child supervisors to be supervised
- children = [
- # Start the Ecto repository
- supervisor(Pleroma.Repo, []),
- # Start the endpoint when the application starts
- supervisor(Pleroma.Web.Endpoint, []),
- # Start your own worker by calling: Pleroma.Worker.start_link(arg1, arg2, arg3)
- # worker(Pleroma.Worker, [arg1, arg2, arg3]),
- worker(Cachex, [:user_cache, [
- default_ttl: 25000,
- ttl_interval: 1000,
- limit: 2500
- ]]),
- worker(Pleroma.Web.Federator, []),
- worker(Pleroma.Stats, []),
- ]
- ++ if Mix.env == :test, do: [], else: [worker(Pleroma.Web.Streamer, [])]
- ++ if !chat_enabled(), do: [], else: [worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
+ children =
+ [
+ # Start the Ecto repository
+ supervisor(Pleroma.Repo, []),
+ # Start the endpoint when the application starts
+ supervisor(Pleroma.Web.Endpoint, []),
+ # Start your own worker by calling: Pleroma.Worker.start_link(arg1, arg2, arg3)
+ # worker(Pleroma.Worker, [arg1, arg2, arg3]),
+ worker(Cachex, [
+ :user_cache,
+ [
+ default_ttl: 25000,
+ ttl_interval: 1000,
+ limit: 2500
+ ]
+ ]),
+ worker(Pleroma.Web.Federator, []),
+ worker(Pleroma.Stats, [])
+ ] ++
+ if Mix.env() == :test,
+ do: [],
+ else:
+ [worker(Pleroma.Web.Streamer, [])] ++
+ if(
+ !chat_enabled(),
+ do: [],
+ else: [worker(Pleroma.Web.ChatChannel.ChatChannelState, [])]
+ )
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
@tag_regex ~r/\#\w+/u
def parse_tags(text, data \\ %{}) do
Regex.scan(@tag_regex, text)
- |> Enum.map(fn (["#" <> tag = full_tag]) -> {full_tag, String.downcase(tag)} end)
- |> (fn map -> if data["sensitive"] in [true, "True", "true", "1"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
+ |> Enum.map(fn ["#" <> tag = full_tag] -> {full_tag, String.downcase(tag)} end)
+ |> (fn map ->
+ if data["sensitive"] in [true, "True", "true", "1"],
+ do: [{"#nsfw", "nsfw"}] ++ map,
+ else: map
+ end).()
end
def parse_mentions(text) do
# Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
- regex = ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
+ regex =
+ ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
Regex.scan(regex, text)
- |> List.flatten
- |> Enum.uniq
- |> Enum.map(fn ("@" <> match = full_match) -> {full_match, User.get_cached_by_nickname(match)} end)
- |> Enum.filter(fn ({_match, user}) -> user end)
+ |> List.flatten()
+ |> Enum.uniq()
+ |> Enum.map(fn "@" <> match = full_match ->
+ {full_match, User.get_cached_by_nickname(match)}
+ end)
+ |> Enum.filter(fn {_match, user} -> user end)
end
@finmoji [
"woollysocks"
]
- @finmoji_with_filenames Enum.map(@finmoji, fn (finmoji) ->
- {finmoji, "/finmoji/128px/#{finmoji}-128.png"}
- end)
+ @finmoji_with_filenames Enum.map(@finmoji, fn finmoji ->
+ {finmoji, "/finmoji/128px/#{finmoji}-128.png"}
+ end)
@emoji_from_file (with {:ok, default} <- File.read("config/emoji.txt") do
custom =
else
_e -> ""
end
+
(default <> "\n" <> custom)
|> String.trim()
|> String.split(~r/\n+/)
- |> Enum.map(fn(line) ->
+ |> Enum.map(fn line ->
[name, file] = String.split(line, ~r/,\s*/)
{name, file}
- end)
+ end)
else
_ -> []
- end)
+ end)
@emoji @finmoji_with_filenames ++ @emoji_from_file
def emojify(text, emoji \\ @emoji)
def emojify(text, nil), do: text
+
def emojify(text, emoji) do
- Enum.reduce(emoji, text, fn ({emoji, file}, text) ->
+ Enum.reduce(emoji, text, fn {emoji, file}, text ->
emoji = HtmlSanitizeEx.strip_tags(emoji)
file = HtmlSanitizeEx.strip_tags(file)
- String.replace(text, ":#{emoji}:", "<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{MediaProxy.url(file)}' />")
+
+ String.replace(
+ text,
+ ":#{emoji}:",
+ "<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{
+ MediaProxy.url(file)
+ }' />"
+ )
end)
end
def get_emoji(text) do
- Enum.filter(@emoji, fn ({emoji, _}) -> String.contains?(text, ":#{emoji}:") end)
+ Enum.filter(@emoji, fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end)
end
def get_custom_emoji() do
@doc "changes http:... links to html links"
def add_links({subs, text}) do
- links = Regex.scan(@link_regex, text)
- |> Enum.map(fn ([url]) -> {Ecto.UUID.generate, url} end)
+ links =
+ Regex.scan(@link_regex, text)
+ |> Enum.map(fn [url] -> {Ecto.UUID.generate(), url} end)
- uuid_text = links
- |> Enum.reduce(text, fn({uuid, url}, acc) -> String.replace(acc, url, uuid) end)
+ uuid_text =
+ links
+ |> Enum.reduce(text, fn {uuid, url}, acc -> String.replace(acc, url, uuid) end)
- subs = subs ++ Enum.map(links, fn({uuid, url}) ->
- {uuid, "<a href='#{url}'>#{url}</a>"}
- end)
+ subs =
+ subs ++
+ Enum.map(links, fn {uuid, url} ->
+ {uuid, "<a href='#{url}'>#{url}</a>"}
+ end)
{subs, uuid_text}
end
@doc "Adds the links to mentioned users"
def add_user_links({subs, text}, mentions) do
- mentions = mentions
- |> Enum.sort_by(fn ({name, _}) -> -String.length(name) end)
- |> Enum.map(fn({name, user}) -> {name, user, Ecto.UUID.generate} end)
-
- uuid_text = mentions
- |> Enum.reduce(text, fn ({match, _user, uuid}, text) ->
- String.replace(text, match, uuid)
- end)
-
- subs = subs ++ Enum.map(mentions, fn ({match, %User{ap_id: ap_id}, uuid}) ->
- short_match = String.split(match, "@") |> tl() |> hd()
- {uuid, "<span><a href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
- end)
+ mentions =
+ mentions
+ |> Enum.sort_by(fn {name, _} -> -String.length(name) end)
+ |> Enum.map(fn {name, user} -> {name, user, Ecto.UUID.generate()} end)
+
+ uuid_text =
+ mentions
+ |> Enum.reduce(text, fn {match, _user, uuid}, text ->
+ String.replace(text, match, uuid)
+ end)
+
+ subs =
+ subs ++
+ Enum.map(mentions, fn {match, %User{ap_id: ap_id}, uuid} ->
+ short_match = String.split(match, "@") |> tl() |> hd()
+ {uuid, "<span><a href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
+ end)
{subs, uuid_text}
end
@doc "Adds the hashtag links"
def add_hashtag_links({subs, text}, tags) do
- tags = tags
- |> Enum.sort_by(fn ({name, _}) -> -String.length(name) end)
- |> Enum.map(fn({name, short}) -> {name, short, Ecto.UUID.generate} end)
-
- uuid_text = tags
- |> Enum.reduce(text, fn ({match, _short, uuid}, text) ->
- String.replace(text, match, uuid)
- end)
-
- subs = subs ++ Enum.map(tags, fn ({_, tag, uuid}) ->
- url = "<a href='#{Pleroma.Web.base_url}/tag/#{tag}' rel='tag'>##{tag}</a>"
- {uuid, url}
- end)
+ tags =
+ tags
+ |> Enum.sort_by(fn {name, _} -> -String.length(name) end)
+ |> Enum.map(fn {name, short} -> {name, short, Ecto.UUID.generate()} end)
+
+ uuid_text =
+ tags
+ |> Enum.reduce(text, fn {match, _short, uuid}, text ->
+ String.replace(text, match, uuid)
+ end)
+
+ subs =
+ subs ++
+ Enum.map(tags, fn {_, tag, uuid} ->
+ url = "<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>##{tag}</a>"
+ {uuid, url}
+ end)
{subs, uuid_text}
end
def finalize({subs, text}) do
- Enum.reduce(subs, text, fn({uuid, replacement}, result_text) ->
+ Enum.reduce(subs, text, fn {uuid, replacement}, result_text ->
String.replace(result_text, uuid, replacement)
end)
end
-
defmodule Pleroma.HTTP do
use HTTPoison.Base
def process_request_options(options) do
config = Application.get_env(:pleroma, :http, [])
proxy = Keyword.get(config, :proxy_url, nil)
+
case proxy do
nil -> options
_ -> options ++ [proxy: proxy]
end
end
-
end
import Ecto.Query
schema "notifications" do
- field :seen, :boolean, default: false
- belongs_to :user, Pleroma.User
- belongs_to :activity, Pleroma.Activity
+ field(:seen, :boolean, default: false)
+ belongs_to(:user, Pleroma.User)
+ belongs_to(:activity, Pleroma.Activity)
timestamps()
end
# TODO: Make generic and unify (see activity_pub.ex)
defp restrict_max(query, %{"max_id" => max_id}) do
- from activity in query, where: activity.id < ^max_id
+ from(activity in query, where: activity.id < ^max_id)
end
+
defp restrict_max(query, _), do: query
defp restrict_since(query, %{"since_id" => since_id}) do
- from activity in query, where: activity.id > ^since_id
+ from(activity in query, where: activity.id > ^since_id)
end
+
defp restrict_since(query, _), do: query
def for_user(user, opts \\ %{}) do
- query = from n in Notification,
- where: n.user_id == ^user.id,
- order_by: [desc: n.id],
- preload: [:activity],
- limit: 20
-
- query = query
- |> restrict_since(opts)
- |> restrict_max(opts)
+ query =
+ from(
+ n in Notification,
+ where: n.user_id == ^user.id,
+ order_by: [desc: n.id],
+ preload: [:activity],
+ limit: 20
+ )
+
+ query =
+ query
+ |> restrict_since(opts)
+ |> restrict_max(opts)
Repo.all(query)
end
def get(%{id: user_id} = _user, id) do
- query = from n in Notification,
- where: n.id == ^id,
- preload: [:activity]
+ query =
+ from(
+ n in Notification,
+ where: n.id == ^id,
+ preload: [:activity]
+ )
notification = Repo.one(query)
+
case notification do
%{user_id: ^user_id} ->
{:ok, notification}
+
_ ->
{:error, "Cannot get notification"}
end
end
def clear(user) do
- query = from n in Notification,
- where: n.user_id == ^user.id
+ query = from(n in Notification, where: n.user_id == ^user.id)
Repo.delete_all(query)
end
def dismiss(%{id: user_id} = _user, id) do
notification = Repo.get(Notification, id)
+
case notification do
%{user_id: ^user_id} ->
Repo.delete(notification)
+
_ ->
{:error, "Cannot dismiss notification"}
end
end
- def create_notifications(%Activity{id: _, data: %{"to" => _, "type" => type}} = activity) when type in ["Create", "Like", "Announce", "Follow"] do
+ def create_notifications(%Activity{id: _, data: %{"to" => _, "type" => type}} = activity)
+ when type in ["Create", "Like", "Announce", "Follow"] do
users = User.get_notified_from_activity(activity)
- notifications = Enum.map(users, fn (user) -> create_notification(activity, user) end)
+ notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
{:ok, notifications}
end
+
def create_notifications(_), do: {:ok, []}
# TODO move to sql, too.
end
end
end
-
import Ecto.{Query, Changeset}
schema "objects" do
- field :data, :map
+ field(:data, :map)
timestamps()
end
def create(data) do
Object.change(%Object{}, %{data: data})
- |> Repo.insert
+ |> Repo.insert()
end
def change(struct, params \\ %{}) do
end
def get_by_ap_id(nil), do: nil
+
def get_by_ap_id(ap_id) do
- Repo.one(from object in Object,
- where: fragment("(?)->>'id' = ?", object.data, ^ap_id))
+ Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
end
def get_cached_by_ap_id(ap_id) do
- if Mix.env == :test do
+ if Mix.env() == :test do
get_by_ap_id(ap_id)
else
key = "object:#{ap_id}"
- Cachex.get!(:user_cache, key, fallback: fn(_) ->
- object = get_by_ap_id(ap_id)
- if object do
- {:commit, object}
- else
- {:ignore, object}
+
+ Cachex.get!(
+ :user_cache,
+ key,
+ fallback: fn _ ->
+ object = get_by_ap_id(ap_id)
+
+ if object do
+ {:commit, object}
+ else
+ {:ignore, object}
+ end
end
- end)
+ )
end
end
{:ok, user} <- opts[:fetcher].(username),
false <- !!user.info["deactivated"],
saved_user_id <- get_session(conn, :user_id),
- {:ok, verified_user} <- verify(user, password, saved_user_id)
- do
+ {:ok, verified_user} <- verify(user, password, saved_user_id) do
conn
|> assign(:user, verified_user)
|> put_session(:user_id, verified_user.id)
end
defp verify(nil, _password, _user_id) do
- Pbkdf2.dummy_checkpw
+ Pbkdf2.dummy_checkpw()
:error
end
defp decode_header(conn) do
with ["Basic " <> header] <- get_req_header(conn, "authorization"),
{:ok, userinfo} <- Base.decode64(header),
- [username, password] <- String.split(userinfo, ":", parts: 2)
- do
+ [username, password] <- String.split(userinfo, ":", parts: 2) do
{:ok, username, password}
end
end
end
def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
+
def call(conn, _) do
- token = case get_req_header(conn, "authorization") do
- ["Bearer " <> header] -> header
- _ -> get_session(conn, :oauth_token)
- end
+ token =
+ case get_req_header(conn, "authorization") do
+ ["Bearer " <> header] -> header
+ _ -> get_session(conn, :oauth_token)
+ end
+
with token when not is_nil(token) <- token,
%Token{user_id: user_id} <- Repo.get_by(Token, token: token),
%User{} = user <- Repo.get(User, user_id),
def schedule_update do
spawn(fn ->
- Process.sleep(1000 * 60 * 60 * 1) # 1 hour
+ # 1 hour
+ Process.sleep(1000 * 60 * 60 * 1)
schedule_update()
end)
+
update_stats()
end
def update_stats do
- peers = from(u in Pleroma.User,
- select: fragment("distinct ?->'host'", u.info),
- where: u.local != ^true)
- |> Repo.all()
+ peers =
+ from(
+ u in Pleroma.User,
+ select: fragment("distinct ?->'host'", u.info),
+ where: u.local != ^true
+ )
+ |> Repo.all()
+
domain_count = Enum.count(peers)
- status_query = from(u in User.local_user_query,
- select: fragment("sum((?->>'note_count')::int)", u.info))
+
+ status_query =
+ from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info))
+
status_count = Repo.one(status_query)
- user_count = Repo.aggregate(User.local_user_query, :count, :id)
+ user_count = Repo.aggregate(User.local_user_query(), :count, :id)
+
Agent.update(__MODULE__, fn _ ->
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
end)
defmodule Pleroma.Upload do
alias Ecto.UUID
alias Pleroma.Web
+
def store(%Plug.Upload{} = file) do
- uuid = UUID.generate
+ uuid = UUID.generate()
upload_folder = Path.join(upload_path(), uuid)
File.mkdir_p!(upload_folder)
result_file = Path.join(upload_folder, file.filename)
File.cp!(file.path, result_file)
# fix content type on some image uploads
- content_type = if file.content_type in [nil, "application/octet-stream"] do
- get_content_type(file.path)
- else
- file.content_type
- end
+ content_type =
+ if file.content_type in [nil, "application/octet-stream"] do
+ get_content_type(file.path)
+ else
+ file.content_type
+ end
%{
"type" => "Image",
- "url" => [%{
- "type" => "Link",
- "mediaType" => content_type,
- "href" => url_for(Path.join(uuid, :cow_uri.urlencode(file.filename)))
- }],
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => content_type,
+ "href" => url_for(Path.join(uuid, :cow_uri.urlencode(file.filename)))
+ }
+ ],
"name" => file.filename,
"uuid" => uuid
}
def store(%{"img" => "data:image/" <> image_data}) do
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
data = Base.decode64!(parsed["data"])
- uuid = UUID.generate
+ uuid = UUID.generate()
upload_folder = Path.join(upload_path(), uuid)
File.mkdir_p!(upload_folder)
filename = Base.encode16(:crypto.hash(:sha256, data)) <> ".#{parsed["filetype"]}"
%{
"type" => "Image",
- "url" => [%{
- "type" => "Link",
- "mediaType" => content_type,
- "href" => url_for(Path.join(uuid, :cow_uri.urlencode(filename)))
- }],
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => content_type,
+ "href" => url_for(Path.join(uuid, :cow_uri.urlencode(filename)))
+ }
+ ],
"name" => filename,
"uuid" => uuid
}
end
def get_content_type(file) do
- match = File.open(file, [:read], fn(f) ->
- case IO.binread(f, 8) do
- <<0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a>> ->
- "image/png"
- <<0x47, 0x49, 0x46, 0x38, _, 0x61, _, _>> ->
- "image/gif"
- <<0xff, 0xd8, 0xff, _, _, _, _, _>> ->
- "image/jpeg"
- <<0x1a, 0x45, 0xdf, 0xa3, _, _, _, _>> ->
- "video/webm"
- <<0x00, 0x00, 0x00, _, 0x66, 0x74, 0x79, 0x70>> ->
- "video/mp4"
- <<0x49, 0x44, 0x33, _, _, _, _, _>> ->
- "audio/mpeg"
- <<0x4f, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00>> ->
- "audio/ogg"
- <<0x52, 0x49, 0x46, 0x46, _, _, _, _>> ->
- "audio/wav"
- _ ->
- "application/octet-stream"
- end
- end)
+ match =
+ File.open(file, [:read], fn f ->
+ case IO.binread(f, 8) do
+ <<0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A>> ->
+ "image/png"
+
+ <<0x47, 0x49, 0x46, 0x38, _, 0x61, _, _>> ->
+ "image/gif"
+
+ <<0xFF, 0xD8, 0xFF, _, _, _, _, _>> ->
+ "image/jpeg"
+
+ <<0x1A, 0x45, 0xDF, 0xA3, _, _, _, _>> ->
+ "video/webm"
+
+ <<0x00, 0x00, 0x00, _, 0x66, 0x74, 0x79, 0x70>> ->
+ "video/mp4"
+
+ <<0x49, 0x44, 0x33, _, _, _, _, _>> ->
+ "audio/mpeg"
+
+ <<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00>> ->
+ "audio/ogg"
+
+ <<0x52, 0x49, 0x46, 0x46, _, _, _, _>> ->
+ "audio/wav"
+
+ _ ->
+ "application/octet-stream"
+ end
+ end)
case match do
{:ok, type} -> type
alias Pleroma.Web.ActivityPub.{Utils, ActivityPub}
schema "users" do
- field :bio, :string
- field :email, :string
- field :name, :string
- field :nickname, :string
- field :password_hash, :string
- field :password, :string, virtual: true
- field :password_confirmation, :string, virtual: true
- field :following, {:array, :string}, default: []
- field :ap_id, :string
- field :avatar, :map
- field :local, :boolean, default: true
- field :info, :map, default: %{}
- field :follower_address, :string
- has_many :notifications, Notification
+ field(:bio, :string)
+ field(:email, :string)
+ field(:name, :string)
+ field(:nickname, :string)
+ field(:password_hash, :string)
+ field(:password, :string, virtual: true)
+ field(:password_confirmation, :string, virtual: true)
+ field(:following, {:array, :string}, default: [])
+ field(:ap_id, :string)
+ field(:avatar, :map)
+ field(:local, :boolean, default: true)
+ field(:info, :map, default: %{})
+ field(:follower_address, :string)
+ has_many(:notifications, Notification)
timestamps()
end
end
def ap_id(%User{nickname: nickname}) do
- "#{Web.base_url}/users/#{nickname}"
+ "#{Web.base_url()}/users/#{nickname}"
end
def ap_followers(%User{} = user) do
def user_info(%User{} = user) do
oneself = if user.local, do: 1, else: 0
+
%{
following_count: length(user.following) - oneself,
note_count: user.info["note_count"] || 0,
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
def remote_user_creation(params) do
- changes = %User{}
- |> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar])
- |> validate_required([:name, :ap_id, :nickname])
- |> unique_constraint(:nickname)
- |> validate_format(:nickname, @email_regex)
- |> validate_length(:bio, max: 5000)
- |> validate_length(:name, max: 100)
- |> put_change(:local, false)
+ changes =
+ %User{}
+ |> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar])
+ |> validate_required([:name, :ap_id, :nickname])
+ |> unique_constraint(:nickname)
+ |> validate_format(:nickname, @email_regex)
+ |> validate_length(:bio, max: 5000)
+ |> validate_length(:name, max: 100)
+ |> put_change(:local, false)
+
if changes.valid? do
case changes.changes[:info]["source_data"] do
%{"followers" => followers} ->
changes
|> put_change(:follower_address, followers)
+
_ ->
followers = User.ap_followers(%User{nickname: changes.changes[:nickname]})
+
changes
|> put_change(:follower_address, followers)
end
end
def password_update_changeset(struct, params) do
- changeset = struct
- |> cast(params, [:password, :password_confirmation])
- |> validate_required([:password, :password_confirmation])
- |> validate_confirmation(:password)
+ changeset =
+ struct
+ |> cast(params, [:password, :password_confirmation])
+ |> validate_required([:password, :password_confirmation])
+ |> validate_confirmation(:password)
if changeset.valid? do
hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
+
changeset
|> put_change(:password_hash, hashed)
else
end
def register_changeset(struct, params \\ %{}) do
- changeset = struct
- |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation])
- |> validate_required([:email, :name, :nickname, :password, :password_confirmation])
- |> validate_confirmation(:password)
- |> unique_constraint(:email)
- |> unique_constraint(:nickname)
- |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
- |> validate_format(:email, @email_regex)
- |> validate_length(:bio, max: 1000)
- |> validate_length(:name, min: 1, max: 100)
+ changeset =
+ struct
+ |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation])
+ |> validate_required([:email, :name, :nickname, :password, :password_confirmation])
+ |> validate_confirmation(:password)
+ |> unique_constraint(:email)
+ |> unique_constraint(:nickname)
+ |> validate_format(:nickname, ~r/^[a-zA-Z\d]+$/)
+ |> validate_format(:email, @email_regex)
+ |> validate_length(:bio, max: 1000)
+ |> validate_length(:name, min: 1, max: 100)
if changeset.valid? do
hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
ap_id = User.ap_id(%User{nickname: changeset.changes[:nickname]})
followers = User.ap_followers(%User{nickname: changeset.changes[:nickname]})
+
changeset
|> put_change(:password_hash, hashed)
|> put_change(:ap_id, ap_id)
ap_followers = followed.follower_address
if following?(follower, followed) or info["deactivated"] do
- {:error,
- "Could not follow user: #{followed.nickname} is already on your list."}
+ {:error, "Could not follow user: #{followed.nickname} is already on your list."}
else
if !followed.local && follower.local && !ap_enabled?(followed) do
Websub.subscribe(follower, followed)
end
- following = [ap_followers | follower.following]
- |> Enum.uniq
+ following =
+ [ap_followers | follower.following]
+ |> Enum.uniq()
- follower = follower
- |> follow_changeset(%{following: following})
- |> update_and_set_cache
+ follower =
+ follower
+ |> follow_changeset(%{following: following})
+ |> update_and_set_cache
{:ok, _} = update_follower_count(followed)
def unfollow(%User{} = follower, %User{} = followed) do
ap_followers = followed.follower_address
+
if following?(follower, followed) and follower.ap_id != followed.ap_id do
- following = follower.following
- |> List.delete(ap_followers)
+ following =
+ follower.following
+ |> List.delete(ap_followers)
- { :ok, follower } = follower
- |> follow_changeset(%{following: following})
- |> update_and_set_cache
+ {:ok, follower} =
+ follower
+ |> follow_changeset(%{following: following})
+ |> update_and_set_cache
{:ok, followed} = update_follower_count(followed)
def get_cached_by_ap_id(ap_id) do
key = "ap_id:#{ap_id}"
- Cachex.get!(:user_cache, key, fallback: fn(_) -> get_by_ap_id(ap_id) end)
+ Cachex.get!(:user_cache, key, fallback: fn _ -> get_by_ap_id(ap_id) end)
end
def get_cached_by_nickname(nickname) do
key = "nickname:#{nickname}"
- Cachex.get!(:user_cache, key, fallback: fn(_) -> get_or_fetch_by_nickname(nickname) end)
+ Cachex.get!(:user_cache, key, fallback: fn _ -> get_or_fetch_by_nickname(nickname) end)
end
def get_by_nickname(nickname) do
def get_cached_user_info(user) do
key = "user_info:#{user.id}"
- Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end)
+ Cachex.get!(:user_cache, key, fallback: fn _ -> user_info(user) end)
end
def fetch_by_nickname(nickname) do
end
def get_or_fetch_by_nickname(nickname) do
- with %User{} = user <- get_by_nickname(nickname) do
+ with %User{} = user <- get_by_nickname(nickname) do
user
- else _e ->
- with [_nick, _domain] <- String.split(nickname, "@"),
- {:ok, user} <- fetch_by_nickname(nickname) do
- user
- else _e -> nil
- end
+ else
+ _e ->
+ with [_nick, _domain] <- String.split(nickname, "@"),
+ {:ok, user} <- fetch_by_nickname(nickname) do
+ user
+ else
+ _e -> nil
+ end
end
end
def get_followers(%User{id: id, follower_address: follower_address}) do
- q = from u in User,
- where: fragment("? <@ ?", ^[follower_address], u.following),
- where: u.id != ^id
+ q =
+ from(
+ u in User,
+ where: fragment("? <@ ?", ^[follower_address], u.following),
+ where: u.id != ^id
+ )
{:ok, Repo.all(q)}
end
def get_friends(%User{id: id, following: following}) do
- q = from u in User,
- where: u.follower_address in ^following,
- where: u.id != ^id
+ q =
+ from(
+ u in User,
+ where: u.follower_address in ^following,
+ where: u.id != ^id
+ )
{:ok, Repo.all(q)}
end
end
def update_note_count(%User{} = user) do
- note_count_query = from a in Object,
- where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data),
- select: count(a.id)
+ note_count_query =
+ from(
+ a in Object,
+ where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data),
+ select: count(a.id)
+ )
note_count = Repo.one(note_count_query)
end
def update_follower_count(%User{} = user) do
- follower_count_query = from u in User,
- where: ^user.follower_address in u.following,
- where: u.id != ^user.id,
- select: count(u.id)
+ follower_count_query =
+ from(
+ u in User,
+ where: ^user.follower_address in u.following,
+ where: u.id != ^user.id,
+ select: count(u.id)
+ )
follower_count = Repo.one(follower_count_query)
end
def get_notified_from_activity(%Activity{recipients: to}) do
- query = from u in User,
- where: u.ap_id in ^to,
- where: u.local == true
+ query =
+ from(
+ u in User,
+ where: u.ap_id in ^to,
+ where: u.local == true
+ )
Repo.all(query)
end
def get_recipients_from_activity(%Activity{recipients: to}) do
- query = from u in User,
- where: u.ap_id in ^to,
- or_where: fragment("? && ?", u.following, ^to)
+ query =
+ from(
+ u in User,
+ where: u.ap_id in ^to,
+ or_where: fragment("? && ?", u.following, ^to)
+ )
- query = from u in query,
- where: u.local == true
+ query = from(u in query, where: u.local == true)
Repo.all(query)
end
if resolve do
User.get_or_fetch_by_nickname(query)
end
- q = from u in User,
- where: fragment("(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)", u.nickname, u.name, ^query),
- limit: 20
+
+ q =
+ from(
+ u in User,
+ where:
+ fragment(
+ "(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)",
+ u.nickname,
+ u.name,
+ ^query
+ ),
+ limit: 20
+ )
+
Repo.all(q)
end
end
def local_user_query() do
- from u in User,
- where: u.local == true
+ from(u in User, where: u.local == true)
end
- def deactivate (%User{} = user) do
+ def deactivate(%User{} = user) do
new_info = Map.put(user.info, "deactivated", true)
cs = User.info_changeset(user, %{info: new_info})
update_and_set_cache(cs)
end
- def delete (%User{} = user) do
+ def delete(%User{} = user) do
{:ok, user} = User.deactivate(user)
# Remove all relationships
- {:ok, followers } = User.get_followers(user)
+ {:ok, followers} = User.get_followers(user)
+
followers
- |> Enum.each(fn (follower) -> User.unfollow(follower, user) end)
+ |> Enum.each(fn follower -> User.unfollow(follower, user) end)
{:ok, friends} = User.get_friends(user)
+
friends
- |> Enum.each(fn (followed) -> User.unfollow(user, followed) end)
+ |> Enum.each(fn followed -> User.unfollow(user, followed) end)
- query = from a in Activity,
- where: a.actor == ^user.ap_id
+ query = from(a in Activity, where: a.actor == ^user.ap_id)
Repo.all(query)
- |> Enum.each(fn (activity) ->
+ |> Enum.each(fn activity ->
case activity.data["type"] do
- "Create" -> ActivityPub.delete(Object.get_by_ap_id(activity.data["object"]["id"]))
- _ -> "Doing nothing" # TODO: Do something with likes, follows, repeats.
+ "Create" ->
+ ActivityPub.delete(Object.get_by_ap_id(activity.data["object"]["id"]))
+
+ # TODO: Do something with likes, follows, repeats.
+ _ ->
+ "Doing nothing"
end
end)
ap_try = ActivityPub.make_user_from_ap_id(ap_id)
case ap_try do
- {:ok, user} -> user
+ {:ok, user} ->
+ user
+
_ ->
case OStatus.make_user(ap_id) do
{:ok, user} -> user
end
# AP style
- def public_key_from_info(%{"source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}}}) do
- key = :public_key.pem_decode(public_key_pem)
- |> hd()
- |> :public_key.pem_entry_decode()
+ def public_key_from_info(%{
+ "source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}}
+ }) do
+ key =
+ :public_key.pem_decode(public_key_pem)
+ |> hd()
+ |> :public_key.pem_entry_decode()
- {:ok, key}
+ {:ok, key}
end
# OStatus Magic Key
defp blank?(n), do: n
def insert_or_update_user(data) do
- data = data
- |> Map.put(:name, blank?(data[:name]) || data[:nickname])
+ data =
+ data
+ |> Map.put(:name, blank?(data[:name]) || data[:nickname])
+
cs = User.remote_user_creation(data)
Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname)
end
with nil <- Activity.get_by_ap_id(map["id"]),
map <- lazy_put_activity_defaults(map),
:ok <- insert_full_object(map) do
- {:ok, activity} = Repo.insert(%Activity{data: map, local: local, actor: map["actor"], recipients: get_recipients(map)})
+ {:ok, activity} =
+ Repo.insert(%Activity{
+ data: map,
+ local: local,
+ actor: map["actor"],
+ recipients: get_recipients(map)
+ })
+
Notification.create_notifications(activity)
stream_out(activity)
{:ok, activity}
def stream_out(activity) do
if activity.data["type"] in ["Create", "Announce"] do
Pleroma.Web.Streamer.stream("user", activity)
+
if Enum.member?(activity.data["to"], "https://www.w3.org/ns/activitystreams#Public") do
Pleroma.Web.Streamer.stream("public", activity)
+
if activity.local do
Pleroma.Web.Streamer.stream("public:local", activity)
end
def create(%{to: to, actor: actor, context: context, object: object} = params) do
additional = params[:additional] || %{}
- local = !(params[:local] == false) # only accept false as false value
+ # only accept false as false value
+ local = !(params[:local] == false)
published = params[:published]
- with create_data <- make_create_data(%{to: to, actor: actor, published: published, context: context, object: object}, additional),
+ with create_data <-
+ make_create_data(
+ %{to: to, actor: actor, published: published, context: context, object: object},
+ additional
+ ),
{:ok, activity} <- insert(create_data, local),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
def accept(%{to: to, actor: actor, object: object} = params) do
- local = !(params[:local] == false) # only accept false as false value
+ # only accept false as false value
+ local = !(params[:local] == false)
with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
{:ok, activity} <- insert(data, local),
end
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
- local = !(params[:local] == false) # only accept false as false value
-
- with data <- %{"to" => to, "cc" => cc, "type" => "Update", "actor" => actor, "object" => object},
+ # only accept false as false value
+ local = !(params[:local] == false)
+
+ with data <- %{
+ "to" => to,
+ "cc" => cc,
+ "type" => "Update",
+ "actor" => actor,
+ "object" => object
+ },
{:ok, activity} <- insert(data, local),
:ok <- maybe_federate(activity) do
{:ok, activity}
end
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
- def like(%User{ap_id: ap_id} = user, %Object{data: %{"id" => _}} = object, activity_id \\ nil, local \\ true) do
+ def like(
+ %User{ap_id: ap_id} = user,
+ %Object{data: %{"id" => _}} = object,
+ activity_id \\ nil,
+ local \\ true
+ ) do
with nil <- get_existing_like(ap_id, object),
like_data <- make_like_data(user, object, activity_id),
{:ok, activity} <- insert(like_data, local),
{:ok, _activity} <- Repo.delete(activity),
{:ok, object} <- remove_like_from_object(activity, object) do
{:ok, object}
- else _e -> {:ok, object}
+ else
+ _e -> {:ok, object}
end
end
- def announce(%User{ap_id: _} = user, %Object{data: %{"id" => _}} = object, activity_id \\ nil, local \\ true) do
+ def announce(
+ %User{ap_id: _} = user,
+ %Object{data: %{"id" => _}} = object,
+ activity_id \\ nil,
+ local \\ true
+ ) do
with true <- is_public?(object),
announce_data <- make_announce_data(user, object, activity_id),
{:ok, activity} <- insert(announce_data, local),
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
unfollow_data <- make_unfollow_data(follower, followed, follow_activity),
{:ok, activity} <- insert(unfollow_data, local),
- :ok, maybe_federate(activity) do
+ :ok,
+ maybe_federate(activity) do
{:ok, activity}
end
end
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
+
data = %{
"type" => "Delete",
"actor" => actor,
"object" => id,
"to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
}
+
with Repo.delete(object),
Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
{:ok, activity} <- insert(data, local),
def fetch_activities_for_context(context, opts \\ %{}) do
public = ["https://www.w3.org/ns/activitystreams#Public"]
- recipients = if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
- query = from activity in Activity
- query = query
+ recipients =
+ if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
+
+ query = from(activity in Activity)
+
+ query =
+ query
|> restrict_blocked(opts)
|> restrict_recipients(recipients, opts["user"])
- query = from activity in query,
- where: fragment("?->>'type' = ? and ?->>'context' = ?", activity.data, "Create", activity.data, ^context),
- order_by: [desc: :id]
+ query =
+ from(
+ activity in query,
+ where:
+ fragment(
+ "?->>'type' = ? and ?->>'context' = ?",
+ activity.data,
+ "Create",
+ activity.data,
+ ^context
+ ),
+ order_by: [desc: :id]
+ )
+
Repo.all(query)
end
# TODO: Make this work properly with unlisted.
def fetch_public_activities(opts \\ %{}) do
q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
+
q
- |> Repo.all
- |> Enum.reverse
+ |> Repo.all()
+ |> Enum.reverse()
end
defp restrict_since(query, %{"since_id" => since_id}) do
- from activity in query, where: activity.id > ^since_id
+ from(activity in query, where: activity.id > ^since_id)
end
+
defp restrict_since(query, _), do: query
defp restrict_tag(query, %{"tag" => tag}) do
- from activity in query,
+ from(
+ activity in query,
where: fragment("? <@ (? #> '{\"object\",\"tag\"}')", ^tag, activity.data)
+ )
end
+
defp restrict_tag(query, _), do: query
defp restrict_recipients(query, [], user), do: query
+
defp restrict_recipients(query, recipients, nil) do
- from activity in query,
- where: fragment("? && ?", ^recipients, activity.recipients)
+ from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
end
+
defp restrict_recipients(query, recipients, user) do
- from activity in query,
+ from(
+ activity in query,
where: fragment("? && ?", ^recipients, activity.recipients),
or_where: activity.actor == ^user.ap_id
+ )
end
defp restrict_limit(query, %{"limit" => limit}) do
- from activity in query,
- limit: ^limit
+ from(activity in query, limit: ^limit)
end
+
defp restrict_limit(query, _), do: query
defp restrict_local(query, %{"local_only" => true}) do
- from activity in query, where: activity.local == true
+ from(activity in query, where: activity.local == true)
end
+
defp restrict_local(query, _), do: query
defp restrict_max(query, %{"max_id" => max_id}) do
- from activity in query, where: activity.id < ^max_id
+ from(activity in query, where: activity.id < ^max_id)
end
+
defp restrict_max(query, _), do: query
defp restrict_actor(query, %{"actor_id" => actor_id}) do
- from activity in query,
- where: activity.actor == ^actor_id
+ from(activity in query, where: activity.actor == ^actor_id)
end
+
defp restrict_actor(query, _), do: query
defp restrict_type(query, %{"type" => type}) when is_binary(type) do
restrict_type(query, %{"type" => [type]})
end
+
defp restrict_type(query, %{"type" => type}) do
- from activity in query,
- where: fragment("?->>'type' = ANY(?)", activity.data, ^type)
+ from(activity in query, where: fragment("?->>'type' = ANY(?)", activity.data, ^type))
end
+
defp restrict_type(query, _), do: query
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
- from activity in query,
+ from(
+ activity in query,
where: fragment("? <@ (? #> '{\"object\",\"likes\"}')", ^ap_id, activity.data)
+ )
end
+
defp restrict_favorited_by(query, _), do: query
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
- from activity in query,
+ from(
+ activity in query,
where: fragment("not (? #> '{\"object\",\"attachment\"}' = ?)", activity.data, ^[])
+ )
end
+
defp restrict_media(query, _), do: query
# Only search through last 100_000 activities by default
defp restrict_recent(query, %{"whole_db" => true}), do: query
+
defp restrict_recent(query, _) do
since = (Repo.aggregate(Activity, :max, :id) || 0) - 100_000
- from activity in query,
- where: activity.id > ^since
+ from(activity in query, where: activity.id > ^since)
end
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
blocks = info["blocks"] || []
- from activity in query,
- where: fragment("not (? = ANY(?))", activity.actor, ^blocks)
+ from(activity in query, where: fragment("not (? = ANY(?))", activity.actor, ^blocks))
end
+
defp restrict_blocked(query, _), do: query
def fetch_activities_query(recipients, opts \\ %{}) do
- base_query = from activity in Activity,
- limit: 20,
- order_by: [fragment("? desc nulls last", activity.id)]
+ base_query =
+ from(
+ activity in Activity,
+ limit: 20,
+ order_by: [fragment("? desc nulls last", activity.id)]
+ )
base_query
|> restrict_recipients(recipients, opts["user"])
def fetch_activities(recipients, opts \\ %{}) do
fetch_activities_query(recipients, opts)
- |> Repo.all
- |> Enum.reverse
+ |> Repo.all()
+ |> Enum.reverse()
end
def upload(file) do
end
def user_data_from_user_object(data) do
- avatar = data["icon"]["url"] && %{
- "type" => "Image",
- "url" => [%{"href" => data["icon"]["url"]}]
- }
-
- banner = data["image"]["url"] && %{
- "type" => "Image",
- "url" => [%{"href" => data["image"]["url"]}]
- }
+ avatar =
+ data["icon"]["url"] &&
+ %{
+ "type" => "Image",
+ "url" => [%{"href" => data["icon"]["url"]}]
+ }
+
+ banner =
+ data["image"]["url"] &&
+ %{
+ "type" => "Image",
+ "url" => [%{"href" => data["image"]["url"]}]
+ }
user_data = %{
ap_id: data["id"],
end
def fetch_and_prepare_user_from_ap_id(ap_id) do
- with {:ok, %{status_code: 200, body: body}} <- @httpoison.get(ap_id, ["Accept": "application/activity+json"]),
- {:ok, data} <- Jason.decode(body) do
+ with {:ok, %{status_code: 200, body: body}} <-
+ @httpoison.get(ap_id, Accept: "application/activity+json"),
+ {:ok, data} <- Jason.decode(body) do
user_data_from_user_object(data)
else
e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
end
def publish(actor, activity) do
- followers = if actor.follower_address in activity.recipients do
- {:ok, followers} = User.get_followers(actor)
- followers |> Enum.filter(&(!&1.local))
- else
- []
- end
+ followers =
+ if actor.follower_address in activity.recipients do
+ {:ok, followers} = User.get_followers(actor)
+ followers |> Enum.filter(&(!&1.local))
+ else
+ []
+ end
- remote_inboxes = (Pleroma.Web.Salmon.remote_users(activity) ++ followers)
- |> Enum.filter(fn (user) -> User.ap_enabled?(user) end)
- |> Enum.map(fn (%{info: %{"source_data" => data}}) ->
- (data["endpoints"] && data["endpoints"]["sharedInbox"]) || data["inbox"]
- end)
- |> Enum.uniq
+ remote_inboxes =
+ (Pleroma.Web.Salmon.remote_users(activity) ++ followers)
+ |> Enum.filter(fn user -> User.ap_enabled?(user) end)
+ |> Enum.map(fn %{info: %{"source_data" => data}} ->
+ (data["endpoints"] && data["endpoints"]["sharedInbox"]) || data["inbox"]
+ end)
+ |> Enum.uniq()
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
json = Jason.encode!(data)
- Enum.each remote_inboxes, fn(inbox) ->
- Federator.enqueue(:publish_single_ap, %{inbox: inbox, json: json, actor: actor, id: activity.data["id"]})
- end
+
+ Enum.each(remote_inboxes, fn inbox ->
+ Federator.enqueue(:publish_single_ap, %{
+ inbox: inbox,
+ json: json,
+ actor: actor,
+ id: activity.data["id"]
+ })
+ end)
end
def publish_one(%{inbox: inbox, json: json, actor: actor, id: id}) do
Logger.info("Federating #{id} to #{inbox}")
host = URI.parse(inbox).host
- signature = Pleroma.Web.HTTPSignatures.sign(actor, %{host: host, "content-length": byte_size(json)})
- @httpoison.post(inbox, json, [{"Content-Type", "application/activity+json"}, {"signature", signature}], hackney: [pool: :default])
+
+ signature =
+ Pleroma.Web.HTTPSignatures.sign(actor, %{host: host, "content-length": byte_size(json)})
+
+ @httpoison.post(
+ inbox,
+ json,
+ [{"Content-Type", "application/activity+json"}, {"signature", signature}],
+ hackney: [pool: :default]
+ )
end
# TODO:
{:ok, object}
else
Logger.info("Fetching #{id} via AP")
+
with true <- String.starts_with?(id, "http"),
- {:ok, %{body: body, status_code: code}} when code in 200..299 <- @httpoison.get(id, [Accept: "application/activity+json"], follow_redirect: true, timeout: 10000, recv_timeout: 20000),
+ {:ok, %{body: body, status_code: code}} when code in 200..299 <-
+ @httpoison.get(
+ id,
+ [Accept: "application/activity+json"],
+ follow_redirect: true,
+ timeout: 10000,
+ recv_timeout: 20000
+ ),
{:ok, data} <- Jason.decode(body),
nil <- Object.get_by_ap_id(data["id"]),
- params <- %{"type" => "Create", "to" => data["to"], "cc" => data["cc"], "actor" => data["attributedTo"], "object" => data},
+ params <- %{
+ "type" => "Create",
+ "to" => data["to"],
+ "cc" => data["cc"],
+ "actor" => data["attributedTo"],
+ "object" => data
+ },
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
{:ok, Object.get_by_ap_id(activity.data["object"]["id"])}
else
- object = %Object{} -> {:ok, object}
+ object = %Object{} ->
+ {:ok, object}
+
e ->
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
+
case OStatus.fetch_activity_from_url(id) do
{:ok, [activity | _]} -> {:ok, Object.get_by_ap_id(activity.data["object"]["id"])}
e -> e
end
def is_public?(activity) do
- "https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++ (activity.data["cc"] || []))
+ "https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++
+ (activity.data["cc"] || []))
end
def visible_for_user?(activity, nil) do
is_public?(activity)
end
+
def visible_for_user?(activity, user) do
x = [user.ap_id | user.following]
- y = (activity.data["to"] ++ (activity.data["cc"] || []))
+ y = activity.data["to"] ++ (activity.data["cc"] || [])
visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y))
end
end
require Logger
- action_fallback :errors
+ action_fallback(:errors)
def user(conn, %{"nickname" => nickname}) do
with %User{} = user <- User.get_cached_by_nickname(nickname),
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
{page, _} = Integer.parse(page)
+
conn
|> put_resp_header("content-type", "application/activity+json")
|> json(UserView.render("following.json", %{user: user, page: page}))
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
{page, _} = Integer.parse(page)
+
conn
|> put_resp_header("content-type", "application/activity+json")
|> json(UserView.render("followers.json", %{user: user, page: page}))
end
end
- def outbox(conn, %{"nickname" => nickname}) do outbox(conn, %{"nickname" => nickname, "max_id" => nil}) end
+ def outbox(conn, %{"nickname" => nickname}) do
+ outbox(conn, %{"nickname" => nickname, "max_id" => nil})
+ end
# TODO: Ensure that this inbox is a recipient of the message
def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
def inbox(conn, params) do
headers = Enum.into(conn.req_headers, %{})
- if !(String.contains?(headers["signature"] || "", params["actor"])) do
+
+ if !String.contains?(headers["signature"] || "", params["actor"]) do
Logger.info("Signature not from author, relayed message, fetching from source")
ActivityPub.fetch_object_from_id(params["object"]["id"])
else
|> fix_tag
end
- def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object) when not is_nil(in_reply_to_id) do
+ def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
+ when not is_nil(in_reply_to_id) do
case ActivityPub.fetch_object_from_id(in_reply_to_id) do
{:ok, replied_object} ->
activity = Activity.get_create_activity_by_object_ap_id(replied_object.data["id"])
+
object
|> Map.put("inReplyTo", replied_object.data["id"])
|> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
|> Map.put("inReplyToStatusId", activity.id)
|> Map.put("conversation", replied_object.data["context"] || object["conversation"])
|> Map.put("context", replied_object.data["context"] || object["conversation"])
+
e ->
Logger.error("Couldn't fetch #{object["inReplyTo"]} #{inspect(e)}")
object
end
end
+
def fix_in_reply_to(object), do: object
def fix_context(object) do
end
def fix_attachments(object) do
- attachments = (object["attachment"] || [])
- |> Enum.map(fn (data) ->
- url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}]
- Map.put(data, "url", url)
- end)
+ attachments =
+ (object["attachment"] || [])
+ |> Enum.map(fn data ->
+ url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}]
+ Map.put(data, "url", url)
+ end)
object
|> Map.put("attachment", attachments)
end
def fix_emoji(object) do
- tags = (object["tag"] || [])
- emoji = tags |> Enum.filter(fn (data) -> data["type"] == "Emoji" and data["icon"] end)
- emoji = emoji |> Enum.reduce(%{}, fn (data, mapping) ->
- name = data["name"]
- if String.starts_with?(name, ":") do
- name = name |> String.slice(1..-2)
- end
+ tags = object["tag"] || []
+ emoji = tags |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end)
+
+ emoji =
+ emoji
+ |> Enum.reduce(%{}, fn data, mapping ->
+ name = data["name"]
+
+ if String.starts_with?(name, ":") do
+ name = name |> String.slice(1..-2)
+ end
- mapping |> Map.put(name, data["icon"]["url"])
- end)
+ mapping |> Map.put(name, data["icon"]["url"])
+ end)
# we merge mastodon and pleroma emoji into a single mapping, to allow for both wire formats
emoji = Map.merge(object["emoji"] || %{}, emoji)
end
def fix_tag(object) do
- tags = (object["tag"] || [])
- |> Enum.filter(fn (data) -> data["type"] == "Hashtag" and data["name"] end)
- |> Enum.map(fn (data) -> String.slice(data["name"], 1..-1) end)
+ tags =
+ (object["tag"] || [])
+ |> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
+ |> Enum.map(fn data -> String.slice(data["name"], 1..-1) end)
combined = (object["tag"] || []) ++ tags
context: object["conversation"],
local: false,
published: data["published"],
- additional: Map.take(data, [
- "cc",
- "id"
- ])
+ additional:
+ Map.take(data, [
+ "cc",
+ "id"
+ ])
}
-
ActivityPub.create(params)
else
%Activity{} = activity -> {:ok, activity}
end
end
- def handle_incoming(%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data) do
+ def handle_incoming(
+ %{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data
+ ) do
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
ActivityPub.accept(%{to: [follower.ap_id], actor: followed.ap_id, object: data, local: true})
+
User.follow(follower, followed)
{:ok, activity}
else
end
end
- def handle_incoming(%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data) do
+ def handle_incoming(
+ %{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data
+ ) do
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
{:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do
end
end
- def handle_incoming(%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data) do
+ def handle_incoming(
+ %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
+ ) do
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
{:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do
end
end
- def handle_incoming(%{"type" => "Update", "object" => %{"type" => "Person"} = object, "actor" => actor_id} = data) do
+ def handle_incoming(
+ %{"type" => "Update", "object" => %{"type" => "Person"} = object, "actor" => actor_id} =
+ data
+ ) do
with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
banner = new_user_data[:info]["banner"]
- update_data = new_user_data
- |> Map.take([:name, :bio, :avatar])
- |> Map.put(:info, Map.merge(actor.info, %{"banner" => banner}))
+
+ update_data =
+ new_user_data
+ |> Map.take([:name, :bio, :avatar])
+ |> Map.put(:info, Map.merge(actor.info, %{"banner" => banner}))
actor
|> User.upgrade_changeset(update_data)
|> User.update_and_set_cache()
- ActivityPub.update(%{local: false, to: data["to"] || [], cc: data["cc"] || [], object: object, actor: actor_id})
+ ActivityPub.update(%{
+ local: false,
+ to: data["to"] || [],
+ cc: data["cc"] || [],
+ object: object,
+ actor: actor_id
+ })
else
e ->
Logger.error(e)
end
# TODO: Make secure.
- def handle_incoming(%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data) do
- object_id = case object_id do
- %{"id" => id} -> id
- id -> id
- end
+ def handle_incoming(
+ %{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data
+ ) do
+ object_id =
+ case object_id do
+ %{"id" => id} -> id
+ id -> id
+ end
+
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
{:ok, activity} <- ActivityPub.delete(object, false) do
_e -> object
end
end
+
def set_reply_to_uri(obj), do: obj
# Prepares the object of an outgoing create activity.
"""
internal -> Mastodon
"""
+
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
- object = object
- |> prepare_object
- data = data
- |> Map.put("object", object)
- |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
+ object =
+ object
+ |> prepare_object
+
+ data =
+ data
+ |> Map.put("object", object)
+ |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
{:ok, data}
end
def prepare_outgoing(%{"type" => type} = data) do
- data = data
- |> maybe_fix_object_url
- |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
+ data =
+ data
+ |> maybe_fix_object_url
+ |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
{:ok, data}
end
case ActivityPub.fetch_object_from_id(data["object"]) do
{:ok, relative_object} ->
if relative_object.data["external_url"] do
- data = data
- |> Map.put("object", relative_object.data["external_url"])
+ data =
+ data
+ |> Map.put("object", relative_object.data["external_url"])
else
data
end
+
e ->
Logger.error("Couldn't fetch #{data["object"]} #{inspect(e)}")
data
end
def add_hashtags(object) do
- tags = (object["tag"] || [])
- |> Enum.map fn (tag) -> %{"href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}", "name" => "##{tag}", "type" => "Hashtag"} end
+ tags =
+ (object["tag"] || [])
+ |> Enum.map(fn tag ->
+ %{
+ "href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}",
+ "name" => "##{tag}",
+ "type" => "Hashtag"
+ }
+ end)
object
|> Map.put("tag", tags)
def add_mention_tags(object) do
recipients = object["to"] ++ (object["cc"] || [])
- mentions = recipients
- |> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn(user) -> %{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"} end)
+
+ mentions =
+ recipients
+ |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user ->
+ %{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"}
+ end)
tags = object["tag"] || []
def add_emoji_tags(object) do
tags = object["tag"] || []
emoji = object["emoji"] || []
- out = emoji |> Enum.map(fn {name, url} ->
- %{"icon" => %{"url" => url, "type" => "Image"},
- "name" => ":" <> name <> ":",
- "type" => "Emoji",
- "updated" => "1970-01-01T00:00:00Z",
- "id" => url}
- end)
+
+ out =
+ emoji
+ |> Enum.map(fn {name, url} ->
+ %{
+ "icon" => %{"url" => url, "type" => "Image"},
+ "name" => ":" <> name <> ":",
+ "type" => "Emoji",
+ "updated" => "1970-01-01T00:00:00Z",
+ "id" => url
+ }
+ end)
object
|> Map.put("tag", tags ++ out)
end
def prepare_attachments(object) do
- attachments = (object["attachment"] || [])
- |> Enum.map(fn (data) ->
- [%{"mediaType" => media_type, "href" => href} | _] = data["url"]
- %{"url" => href, "mediaType" => media_type, "name" => data["name"], "type" => "Document"}
- end)
+ attachments =
+ (object["attachment"] || [])
+ |> Enum.map(fn data ->
+ [%{"mediaType" => media_type, "href" => href} | _] = data["url"]
+ %{"url" => href, "mediaType" => media_type, "name" => data["name"], "type" => "Document"}
+ end)
object
|> Map.put("attachment", attachments)
defp user_upgrade_task(user) do
old_follower_address = User.ap_followers(user)
- q = from u in User,
- where: ^old_follower_address in u.following,
- update: [set: [following: fragment("array_replace(?,?,?)", u.following, ^old_follower_address, ^user.follower_address)]]
+
+ q =
+ from(
+ u in User,
+ where: ^old_follower_address in u.following,
+ update: [
+ set: [
+ following:
+ fragment(
+ "array_replace(?,?,?)",
+ u.following,
+ ^old_follower_address,
+ ^user.follower_address
+ )
+ ]
+ ]
+ )
+
Repo.update_all(q, [])
maybe_retire_websub(user.ap_id)
# Only do this for recent activties, don't go through the whole db.
# Only look at the last 1000 activities.
since = (Repo.aggregate(Activity, :max, :id) || 0) - 1_000
- q = from a in Activity,
- where: ^old_follower_address in a.recipients,
- where: a.id > ^since,
- update: [set: [recipients: fragment("array_replace(?,?,?)", a.recipients, ^old_follower_address, ^user.follower_address)]]
+
+ q =
+ from(
+ a in Activity,
+ where: ^old_follower_address in a.recipients,
+ where: a.id > ^since,
+ update: [
+ set: [
+ recipients:
+ fragment(
+ "array_replace(?,?,?)",
+ a.recipients,
+ ^old_follower_address,
+ ^user.follower_address
+ )
+ ]
+ ]
+ )
+
Repo.update_all(q, [])
end
def upgrade_user_from_ap_id(ap_id, async \\ true) do
with %User{local: false} = user <- User.get_by_ap_id(ap_id),
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do
- data = data
- |> Map.put(:info, Map.merge(user.info, data[:info]))
+ data =
+ data
+ |> Map.put(:info, Map.merge(user.info, data[:info]))
already_ap = User.ap_enabled?(user)
- {:ok, user} = User.upgrade_changeset(user, data)
- |> Repo.update()
+
+ {:ok, user} =
+ User.upgrade_changeset(user, data)
+ |> Repo.update()
if !already_ap do
# This could potentially take a long time, do it in the background
def maybe_retire_websub(ap_id) do
# some sanity checks
- if is_binary(ap_id) && (String.length(ap_id) > 8) do
- q = from ws in Pleroma.Web.Websub.WebsubClientSubscription,
- where: fragment("? like ?", ws.topic, ^"#{ap_id}%")
+ if is_binary(ap_id) && String.length(ap_id) > 8 do
+ q =
+ from(
+ ws in Pleroma.Web.Websub.WebsubClientSubscription,
+ where: fragment("? like ?", ws.topic, ^"#{ap_id}%")
+ )
+
Repo.delete_all(q)
end
end
end
def make_date do
- DateTime.utc_now() |> DateTime.to_iso8601
+ DateTime.utc_now() |> DateTime.to_iso8601()
end
def generate_activity_id do
end
def generate_object_id do
- Helpers.o_status_url(Endpoint, :object, UUID.generate)
+ Helpers.o_status_url(Endpoint, :object, UUID.generate())
end
def generate_id(type) do
- "#{Web.base_url()}/#{type}/#{UUID.generate}"
+ "#{Web.base_url()}/#{type}/#{UUID.generate()}"
end
@doc """
Enqueues an activity for federation if it's local
"""
def maybe_federate(%Activity{local: true} = activity) do
- priority = case activity.data["type"] do
- "Delete" -> 10
- "Create" -> 1
- _ -> 5
- end
+ priority =
+ case activity.data["type"] do
+ "Delete" -> 10
+ "Create" -> 1
+ _ -> 5
+ end
+
Pleroma.Web.Federator.enqueue(:publish, activity, priority)
:ok
end
+
def maybe_federate(_), do: :ok
@doc """
also adds it to an included object
"""
def lazy_put_activity_defaults(map) do
- map = map
- |> Map.put_new_lazy("id", &generate_activity_id/0)
- |> Map.put_new_lazy("published", &make_date/0)
+ map =
+ map
+ |> Map.put_new_lazy("id", &generate_activity_id/0)
+ |> Map.put_new_lazy("published", &make_date/0)
if is_map(map["object"]) do
object = lazy_put_object_defaults(map["object"])
@doc """
Inserts a full object if it is contained in an activity.
"""
- def insert_full_object(%{"object" => %{"type" => type} = object_data}) when is_map(object_data) and type in ["Note"] do
+ def insert_full_object(%{"object" => %{"type" => type} = object_data})
+ when is_map(object_data) and type in ["Note"] do
with {:ok, _} <- Object.create(object_data) do
:ok
end
end
+
def insert_full_object(_), do: :ok
def update_object_in_activities(%{data: %{"id" => id}} = object) do
# Alternatively, just don't do this and fetch the current object each time. Most
# could probably be taken from cache.
relevant_activities = Activity.all_by_object_ap_id(id)
- Enum.map(relevant_activities, fn (activity) ->
+
+ Enum.map(relevant_activities, fn activity ->
new_activity_data = activity.data |> Map.put("object", object.data)
changeset = Changeset.change(activity, data: new_activity_data)
Repo.update(changeset)
Returns an existing like if a user already liked an object
"""
def get_existing_like(actor, %{data: %{"id" => id}}) do
- query = from activity in Activity,
- where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
- # this is to use the index
- where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^id),
- where: fragment("(?)->>'type' = 'Like'", activity.data)
+ query =
+ from(
+ activity in Activity,
+ where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
+ # this is to use the index
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
+ activity.data,
+ ^id
+ ),
+ where: fragment("(?)->>'type' = 'Like'", activity.data)
+ )
Repo.one(query)
end
end
def update_element_in_object(property, element, object) do
- with new_data <- object.data |> Map.put("#{property}_count", length(element)) |> Map.put("#{property}s", element),
+ with new_data <-
+ object.data |> Map.put("#{property}_count", length(element))
+ |> Map.put("#{property}s", element),
changeset <- Changeset.change(object, data: new_data),
{:ok, object} <- Repo.update(changeset),
- _ <- update_object_in_activities(object) do
+ _ <- update_object_in_activities(object) do
{:ok, object}
end
end
end
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
- with likes <- [actor | (object.data["likes"] || [])] |> Enum.uniq do
+ with likes <- [actor | object.data["likes"] || []] |> Enum.uniq() do
update_likes_in_object(likes, object)
end
end
if activity_id, do: Map.put(data, "id", activity_id), else: data
end
- def fetch_latest_follow(%User{ap_id: follower_id},
- %User{ap_id: followed_id}) do
- query = from activity in Activity,
- where: fragment("? @> ?", activity.data, ^%{type: "Follow", actor: follower_id,
- object: followed_id}),
- order_by: [desc: :id],
- limit: 1
+ def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
+ query =
+ from(
+ activity in Activity,
+ where:
+ fragment(
+ "? @> ?",
+ activity.data,
+ ^%{type: "Follow", actor: follower_id, object: followed_id}
+ ),
+ order_by: [desc: :id],
+ limit: 1
+ )
+
Repo.one(query)
end
@doc """
Make announce activity data for the given actor and object
"""
- def make_announce_data(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object, activity_id) do
+ def make_announce_data(
+ %User{ap_id: ap_id} = user,
+ %Object{data: %{"id" => id}} = object,
+ activity_id
+ ) do
data = %{
"type" => "Announce",
"actor" => ap_id,
end
def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
- with announcements <- [actor | (object.data["announcements"] || [])] |> Enum.uniq do
+ with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do
update_element_in_object("announcement", announcements, object)
end
end
}
end
-
#### Create-related helpers
def make_create_data(params, additional) do
published = params.published || make_date()
+
%{
"type" => "Create",
- "to" => params.to |> Enum.uniq,
+ "to" => params.to |> Enum.uniq(),
"actor" => params.actor.ap_id,
"object" => params.object,
"published" => published,
{:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"])
public_key = :public_key.pem_entry_encode(:RSAPublicKey, public_key)
public_key = :public_key.pem_encode([public_key])
+
%{
"id" => user.ap_id,
"type" => "Person",
"publicKeyPem" => public_key
},
"endpoints" => %{
- "sharedInbox" => "#{Pleroma.Web.Endpoint.url}/inbox"
+ "sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox"
},
"icon" => %{
"type" => "Image",
def collection(collection, iri, page) do
offset = (page - 1) * 10
items = Enum.slice(collection, offset, 10)
- items = Enum.map(items, fn (user) -> user.ap_id end)
+ items = Enum.map(items, fn user -> user.ap_id end)
+
map = %{
"id" => "#{iri}?page=#{page}",
"type" => "OrderedCollectionPage",
"totalItems" => length(collection),
"orderedItems" => items
}
+
if offset < length(collection) do
- Map.put(map, "next", "#{iri}?page=#{page+1}")
+ Map.put(map, "next", "#{iri}?page=#{page + 1}")
end
end
def render("following.json", %{user: user, page: page}) do
{:ok, following} = User.get_friends(user)
+
collection(following, "#{user.ap_id}/following", page)
|> Map.merge(Utils.make_json_ld_header())
end
def render("following.json", %{user: user}) do
{:ok, following} = User.get_friends(user)
+
%{
"id" => "#{user.ap_id}/following",
"type" => "OrderedCollection",
def render("followers.json", %{user: user, page: page}) do
{:ok, followers} = User.get_followers(user)
+
collection(followers, "#{user.ap_id}/followers", page)
|> Map.merge(Utils.make_json_ld_header())
end
def render("followers.json", %{user: user}) do
{:ok, followers} = User.get_followers(user)
+
%{
"id" => "#{user.ap_id}/followers",
"type" => "OrderedCollection",
activities = Enum.reverse(activities)
max_id = Enum.at(activities, 0).id
- collection = Enum.map(activities, fn (act) ->
- {:ok, data} = Transmogrifier.prepare_outgoing(act.data)
- data
- end)
+ collection =
+ Enum.map(activities, fn act ->
+ {:ok, data} = Transmogrifier.prepare_outgoing(act.data)
+ data
+ end)
iri = "#{user.ap_id}/outbox"
+
page = %{
"id" => "#{iri}?max_id=#{max_id}",
"type" => "OrderedCollectionPage",
"partOf" => iri,
"totalItems" => info.note_count,
"orderedItems" => collection,
- "next" => "#{iri}?max_id=#{min_id-1}",
+ "next" => "#{iri}?max_id=#{min_id - 1}"
}
if max_qid == nil do
## Channels
# channel "room:*", Pleroma.Web.RoomChannel
if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
- channel "chat:*", Pleroma.Web.ChatChannel
+ channel("chat:*", Pleroma.Web.ChatChannel)
end
## Transports
- transport :websocket, Phoenix.Transports.WebSocket
+ transport(:websocket, Phoenix.Transports.WebSocket)
# transport :longpoll, Phoenix.Transports.LongPoll
# Socket params are passed from the client and can
end
def handle_info(:after_join, socket) do
- push socket, "messages", %{messages: ChatChannelState.messages()}
+ push(socket, "messages", %{messages: ChatChannelState.messages()})
{:noreply, socket}
end
def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do
text = String.trim(text)
+
if String.length(text) > 0 do
author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("account.json", user: author)
message = ChatChannelState.add_message(%{text: text, author: author})
- broadcast! socket, "new_msg", message
+ broadcast!(socket, "new_msg", message)
end
+
{:noreply, socket}
end
end
end
def messages() do
- Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse end)
+ Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse() end)
end
end
def delete(activity_id, user) do
with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
%Object{} = object <- Object.get_by_ap_id(object_id),
- true <- user.info["is_moderator"] || (user.ap_id == object.data["actor"]),
+ true <- user.info["is_moderator"] || user.ap_id == object.data["actor"],
{:ok, delete} <- ActivityPub.delete(object) do
{:ok, delete}
end
end
end
- def get_visibility(%{"visibility" => visibility}) when visibility in ~w{public unlisted private direct}, do: visibility
+ def get_visibility(%{"visibility" => visibility})
+ when visibility in ~w{public unlisted private direct},
+ do: visibility
+
def get_visibility(%{"in_reply_to_status_id" => status_id}) when not is_nil(status_id) do
inReplyTo = get_replied_to_activity(status_id)
Pleroma.Web.MastodonAPI.StatusView.get_visibility(inReplyTo.data["object"])
end
+
def get_visibility(_), do: "public"
@instance Application.get_env(:pleroma, :instance)
@limit Keyword.get(@instance, :limit)
def post(user, %{"status" => status} = data) do
visibility = get_visibility(data)
+
with status <- String.trim(status),
length when length in 1..@limit <- String.length(status),
attachments <- attachments_from_ids(data["media_ids"]),
inReplyTo <- get_replied_to_activity(data["in_reply_to_status_id"]),
{to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
tags <- Formatter.parse_tags(status, data),
- content_html <- make_content_html(status, mentions, attachments, tags, data["no_attachment_links"]),
+ content_html <-
+ make_content_html(status, mentions, attachments, tags, data["no_attachment_links"]),
context <- make_context(inReplyTo),
cw <- data["spoiler_text"],
- object <- make_note_data(user.ap_id, to, context, content_html, attachments, inReplyTo, tags, cw, cc),
- object <- Map.put(object, "emoji", Formatter.get_emoji(status) |> Enum.reduce(%{}, fn({name, file}, acc) -> Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url}#{file}") end)) do
- res = ActivityPub.create(%{to: to, actor: user, context: context, object: object, additional: %{"cc" => cc}})
+ object <-
+ make_note_data(
+ user.ap_id,
+ to,
+ context,
+ content_html,
+ attachments,
+ inReplyTo,
+ tags,
+ cw,
+ cc
+ ),
+ object <-
+ Map.put(
+ object,
+ "emoji",
+ Formatter.get_emoji(status)
+ |> Enum.reduce(%{}, fn {name, file}, acc ->
+ Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
+ end)
+ ) do
+ res =
+ ActivityPub.create(%{
+ to: to,
+ actor: user,
+ context: context,
+ object: object,
+ additional: %{"cc" => cc}
+ })
+
User.increase_note_count(user)
res
end
end
def update(user) do
- ActivityPub.update(%{local: true, to: [user.follower_address], cc: [], actor: user.ap_id, object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})})
+ ActivityPub.update(%{
+ local: true,
+ to: [user.follower_address],
+ cc: [],
+ actor: user.ap_id,
+ object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
+ })
end
end
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
+
if activity.data["type"] == "Create" do
activity
else
def get_replied_to_activity(id) when not is_nil(id) do
Repo.get(Activity, id)
end
+
def get_replied_to_activity(_), do: nil
def attachments_from_ids(ids) do
- Enum.map(ids || [], fn (media_id) ->
+ Enum.map(ids || [], fn media_id ->
Repo.get(Object, media_id).data
end)
end
def to_for_user_and_mentions(user, mentions, inReplyTo, "public") do
to = ["https://www.w3.org/ns/activitystreams#Public"]
- mentioned_users = Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end)
+ mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
cc = [user.follower_address | mentioned_users]
+
if inReplyTo do
{to, Enum.uniq([inReplyTo.data["actor"] | cc])}
else
end
def to_for_user_and_mentions(user, mentions, inReplyTo, "direct") do
- mentioned_users = Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end)
+ mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
+
if inReplyTo do
{Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
else
end
def make_context(%Activity{data: %{"context" => context}}), do: context
- def make_context(_), do: Utils.generate_context_id
+ def make_context(_), do: Utils.generate_context_id()
def maybe_add_attachments(text, attachments, _no_links = true), do: text
+
def maybe_add_attachments(text, attachments, _no_links) do
add_attachments(text, attachments)
end
+
def add_attachments(text, attachments) do
- attachment_text = Enum.map(attachments, fn
- (%{"url" => [%{"href" => href} | _]}) ->
- name = URI.decode(Path.basename(href))
- "<a href=\"#{href}\" class='attachment'>#{shortname(name)}</a>"
- _ -> ""
- end)
+ attachment_text =
+ Enum.map(attachments, fn
+ %{"url" => [%{"href" => href} | _]} ->
+ name = URI.decode(Path.basename(href))
+ "<a href=\"#{href}\" class='attachment'>#{shortname(name)}</a>"
+
+ _ ->
+ ""
+ end)
+
Enum.join([text | attachment_text], "<br>")
end
def format_input(text, mentions, tags) do
text
- |> Formatter.html_escape
+ |> Formatter.html_escape()
|> String.replace("\n", "<br>")
- |> (&({[], &1})).()
- |> Formatter.add_links
+ |> (&{[], &1}).()
+ |> Formatter.add_links()
|> Formatter.add_user_links(mentions)
|> Formatter.add_hashtag_links(tags)
- |> Formatter.finalize
+ |> Formatter.finalize()
end
def add_tag_links(text, tags) do
- tags = tags
- |> Enum.sort_by(fn ({tag, _}) -> -String.length(tag) end)
+ tags =
+ tags
+ |> Enum.sort_by(fn {tag, _} -> -String.length(tag) end)
- Enum.reduce(tags, text, fn({full, tag}, text) ->
- url = "#<a href='#{Pleroma.Web.base_url}/tag/#{tag}' rel='tag'>#{tag}</a>"
+ Enum.reduce(tags, text, fn {full, tag}, text ->
+ url = "#<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{tag}</a>"
String.replace(text, full, url)
end)
end
- def make_note_data(actor, to, context, content_html, attachments, inReplyTo, tags, cw \\ nil, cc \\ []) do
- object = %{
- "type" => "Note",
- "to" => to,
- "cc" => cc,
- "content" => content_html,
- "summary" => cw,
- "context" => context,
- "attachment" => attachments,
- "actor" => actor,
- "tag" => tags |> Enum.map(fn ({_, tag}) -> tag end)
- }
+ def make_note_data(
+ actor,
+ to,
+ context,
+ content_html,
+ attachments,
+ inReplyTo,
+ tags,
+ cw \\ nil,
+ cc \\ []
+ ) do
+ object = %{
+ "type" => "Note",
+ "to" => to,
+ "cc" => cc,
+ "content" => content_html,
+ "summary" => cw,
+ "context" => context,
+ "attachment" => attachments,
+ "actor" => actor,
+ "tag" => tags |> Enum.map(fn {_, tag} -> tag end)
+ }
if inReplyTo do
object
end
def date_to_asctime(date) do
- with {:ok, date, _offset} <- date |> DateTime.from_iso8601 do
+ with {:ok, date, _offset} <- date |> DateTime.from_iso8601() do
format_asctime(date)
- else _e ->
+ else
+ _e ->
""
end
end
def to_masto_date(%NaiveDateTime{} = date) do
date
- |> NaiveDateTime.to_iso8601
+ |> NaiveDateTime.to_iso8601()
|> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
end
def to_masto_date(date) do
try do
date
- |> NaiveDateTime.from_iso8601!
- |> NaiveDateTime.to_iso8601
+ |> NaiveDateTime.from_iso8601!()
+ |> NaiveDateTime.to_iso8601()
|> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
rescue
_e -> ""
use Phoenix.Endpoint, otp_app: :pleroma
if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
- socket "/socket", Pleroma.Web.UserSocket
+ socket("/socket", Pleroma.Web.UserSocket)
end
- socket "/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket
+
+ socket("/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket)
# Serve at "/" the static files from "priv/static" directory.
#
# You should set gzip to true if you are running phoenix.digest
# when deploying your static files in production.
- plug Plug.Static,
- at: "/media", from: "uploads", gzip: false
- plug Plug.Static,
- at: "/", from: :pleroma,
+ plug(Plug.Static, at: "/media", from: "uploads", gzip: false)
+
+ plug(
+ Plug.Static,
+ at: "/",
+ from: :pleroma,
only: ~w(index.html static finmoji emoji packs sounds images instance sw.js)
+ )
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
- plug Phoenix.CodeReloader
+ plug(Phoenix.CodeReloader)
end
- plug TrailingFormatPlug
- plug Plug.RequestId
- plug Plug.Logger
+ plug(TrailingFormatPlug)
+ plug(Plug.RequestId)
+ plug(Plug.Logger)
- plug Plug.Parsers,
+ plug(
+ Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Jason
+ )
- plug Plug.MethodOverride
- plug Plug.Head
+ plug(Plug.MethodOverride)
+ plug(Plug.Head)
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
- plug Plug.Session,
+ plug(
+ Plug.Session,
store: :cookie,
key: "_pleroma_key",
signing_salt: "CqaoopA2"
+ )
- plug Pleroma.Web.Router
+ plug(Pleroma.Web.Router)
@doc """
Dynamically loads configuration from the system environment
def start_link do
spawn(fn ->
- Process.sleep(1000 * 60 * 1) # 1 minute
+ # 1 minute
+ Process.sleep(1000 * 60 * 1)
enqueue(:refresh_subscriptions, nil)
end)
- GenServer.start_link(__MODULE__, %{
- in: {:sets.new(), []},
- out: {:sets.new(), []}
- }, name: __MODULE__)
+
+ GenServer.start_link(
+ __MODULE__,
+ %{
+ in: {:sets.new(), []},
+ out: {:sets.new(), []}
+ },
+ name: __MODULE__
+ )
end
def handle(:refresh_subscriptions, _) do
Logger.debug("Federator running refresh subscriptions")
Websub.refresh_subscriptions()
+
spawn(fn ->
- Process.sleep(1000 * 60 * 60 * 6) # 6 hours
+ # 6 hours
+ Process.sleep(1000 * 60 * 60 * 6)
enqueue(:refresh_subscriptions, nil)
end)
end
def handle(:request_subscription, websub) do
Logger.debug("Refreshing #{websub.topic}")
- with {:ok, websub } <- Websub.request_subscription(websub) do
+
+ with {:ok, websub} <- Websub.request_subscription(websub) do
Logger.debug("Successfully refreshed #{websub.topic}")
else
_e -> Logger.debug("Couldn't refresh #{websub.topic}")
def handle(:publish, activity) do
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
+
with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do
{:ok, actor} = WebFinger.ensure_keys_present(actor)
+
if ActivityPub.is_public?(activity) do
Logger.info(fn -> "Sending #{activity.data["id"]} out via WebSub" end)
Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)
end
def handle(:verify_websub, websub) do
- Logger.debug(fn -> "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" end)
+ Logger.debug(fn ->
+ "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})"
+ end)
+
@websub.verify(websub)
end
def handle(:incoming_ap_doc, params) do
Logger.info("Handling incoming AP activity")
+
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
nil <- Activity.get_by_ap_id(params["id"]),
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
else
%Activity{} ->
Logger.info("Already had #{params["id"]}")
+
e ->
# Just drop those for now
Logger.info("Unhandled activity")
- Logger.info(Poison.encode!(params, [pretty: 2]))
+ Logger.info(Poison.encode!(params, pretty: 2))
end
end
signature = @websub.sign(secret || "", xml)
Logger.debug(fn -> "Pushing #{topic} to #{callback}" end)
- with {:ok, %{status_code: code}} <- @httpoison.post(callback, xml, [
- {"Content-Type", "application/atom+xml"},
- {"X-Hub-Signature", "sha1=#{signature}"}
- ], timeout: 10000, recv_timeout: 20000, hackney: [pool: :default]) do
+ with {:ok, %{status_code: code}} <-
+ @httpoison.post(
+ callback,
+ xml,
+ [
+ {"Content-Type", "application/atom+xml"},
+ {"X-Hub-Signature", "sha1=#{signature}"}
+ ],
+ timeout: 10000,
+ recv_timeout: 20000,
+ hackney: [pool: :default]
+ ) do
Logger.debug(fn -> "Pushed to #{callback}, code #{code}" end)
- else e ->
+ else
+ e ->
Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end)
end
end
def enqueue(type, payload, priority \\ 1) do
if @federating do
- if Mix.env == :test do
+ if Mix.env() == :test do
handle(type, payload)
else
GenServer.cast(__MODULE__, {:enqueue, type, payload, priority})
end
def maybe_start_job(running_jobs, queue) do
- if (:sets.size(running_jobs) < @max_jobs) && queue != [] do
+ if :sets.size(running_jobs) < @max_jobs && queue != [] do
{{type, payload}, queue} = queue_pop(queue)
{:ok, pid} = Task.start(fn -> handle(type, payload) end)
mref = Process.monitor(pid)
end
end
- def handle_cast({:enqueue, type, payload, priority}, state) when type in [:incoming_doc, :incoming_ap_doc] do
+ def handle_cast({:enqueue, type, payload, priority}, state)
+ when type in [:incoming_doc, :incoming_ap_doc] do
%{in: {i_running_jobs, i_queue}, out: {o_running_jobs, o_queue}} = state
i_queue = enqueue_sorted(i_queue, {type, payload}, 1)
{i_running_jobs, i_queue} = maybe_start_job(i_running_jobs, i_queue)
def enqueue_sorted(queue, element, priority) do
[%{item: element, priority: priority} | queue]
- |> Enum.sort_by(fn (%{priority: priority}) -> priority end)
+ |> Enum.sort_by(fn %{priority: priority} -> priority end)
end
def queue_pop([%{item: element} | queue]) do
def ap_enabled_actor(id) do
user = User.get_by_ap_id(id)
+
if User.ap_enabled?(user) do
{:ok, user}
else
require Logger
def create_app(conn, params) do
- with cs <- App.register_changeset(%App{}, params) |> IO.inspect,
- {:ok, app} <- Repo.insert(cs) |> IO.inspect do
+ with cs <- App.register_changeset(%App{}, params) |> IO.inspect(),
+ {:ok, app} <- Repo.insert(cs) |> IO.inspect() do
res = %{
id: app.id,
client_id: app.client_id,
def update_credentials(%{assigns: %{user: user}} = conn, params) do
original_user = user
- params = if bio = params["note"] do
- Map.put(params, "bio", bio)
- else
- params
- end
- params = if name = params["display_name"] do
- Map.put(params, "name", name)
- else
- params
- end
+ params =
+ if bio = params["note"] do
+ Map.put(params, "bio", bio)
+ else
+ params
+ end
- user = if avatar = params["avatar"] do
- with %Plug.Upload{} <- avatar,
- {:ok, object} <- ActivityPub.upload(avatar),
- change = Ecto.Changeset.change(user, %{avatar: object.data}),
- {:ok, user} = User.update_and_set_cache(change) do
- user
+ params =
+ if name = params["display_name"] do
+ Map.put(params, "name", name)
else
- _e -> user
+ params
end
- else
- user
- end
- user = if banner = params["header"] do
- with %Plug.Upload{} <- banner,
- {:ok, object} <- ActivityPub.upload(banner),
- new_info <- Map.put(user.info, "banner", object.data),
- change <- User.info_changeset(user, %{info: new_info}),
- {:ok, user} <- User.update_and_set_cache(change) do
+ user =
+ if avatar = params["avatar"] do
+ with %Plug.Upload{} <- avatar,
+ {:ok, object} <- ActivityPub.upload(avatar),
+ change = Ecto.Changeset.change(user, %{avatar: object.data}),
+ {:ok, user} = User.update_and_set_cache(change) do
+ user
+ else
+ _e -> user
+ end
+ else
user
+ end
+
+ user =
+ if banner = params["header"] do
+ with %Plug.Upload{} <- banner,
+ {:ok, object} <- ActivityPub.upload(banner),
+ new_info <- Map.put(user.info, "banner", object.data),
+ change <- User.info_changeset(user, %{info: new_info}),
+ {:ok, user} <- User.update_and_set_cache(change) do
+ user
+ else
+ _e -> user
+ end
else
- _e -> user
+ user
end
- else
- user
- end
with changeset <- User.update_changeset(user, params),
{:ok, user} <- User.update_and_set_cache(changeset) do
if original_user != user do
CommonAPI.update(user)
end
- json conn, AccountView.render("account.json", %{user: user})
+
+ json(conn, AccountView.render("account.json", %{user: user}))
else
_e ->
conn
account = AccountView.render("account.json", %{user: user})
json(conn, account)
else
- _e -> conn
- |> put_status(404)
- |> json(%{error: "Can't find user"})
+ _e ->
+ conn
+ |> put_status(404)
+ |> json(%{error: "Can't find user"})
end
end
def masto_instance(conn, _params) do
response = %{
- uri: Web.base_url,
+ uri: Web.base_url(),
title: Keyword.get(@instance, :name),
description: "A Pleroma instance, an alternative fediverse server",
version: Keyword.get(@instance, :version),
email: Keyword.get(@instance, :email),
urls: %{
- streaming_api: String.replace(Web.base_url, ["http","https"], "wss")
+ streaming_api: String.replace(Web.base_url(), ["http", "https"], "wss")
},
- stats: Stats.get_stats,
- thumbnail: Web.base_url <> "/instance/thumbnail.jpeg",
+ stats: Stats.get_stats(),
+ thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
max_toot_chars: Keyword.get(@instance, :limit)
}
end
def peers(conn, _params) do
- json(conn, Stats.get_peers)
+ json(conn, Stats.get_peers())
end
defp mastodonized_emoji do
Pleroma.Formatter.get_custom_emoji()
|> Enum.map(fn {shortcode, relative_url} ->
- url = to_string URI.merge(Web.base_url(), relative_url)
+ url = to_string(URI.merge(Web.base_url(), relative_url))
+
%{
"shortcode" => shortcode,
"static_url" => url,
def custom_emojis(conn, _params) do
mastodon_emoji = mastodonized_emoji()
- json conn, mastodon_emoji
+ json(conn, mastodon_emoji)
end
defp add_link_headers(conn, method, activities, param \\ false) do
last = List.last(activities)
first = List.first(activities)
+
if last do
min = last.id
max = first.id
- {next_url, prev_url} = if param do
- {
- mastodon_api_url(Pleroma.Web.Endpoint, method, param, max_id: min),
- mastodon_api_url(Pleroma.Web.Endpoint, method, param, since_id: max)
- }
- else
- {
- mastodon_api_url(Pleroma.Web.Endpoint, method, max_id: min),
- mastodon_api_url(Pleroma.Web.Endpoint, method, since_id: max)
- }
- end
+
+ {next_url, prev_url} =
+ if param do
+ {
+ mastodon_api_url(Pleroma.Web.Endpoint, method, param, max_id: min),
+ mastodon_api_url(Pleroma.Web.Endpoint, method, param, since_id: max)
+ }
+ else
+ {
+ mastodon_api_url(Pleroma.Web.Endpoint, method, max_id: min),
+ mastodon_api_url(Pleroma.Web.Endpoint, method, since_id: max)
+ }
+ end
+
conn
|> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"")
else
end
def home_timeline(%{assigns: %{user: user}} = conn, params) do
- params = params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("blocking_user", user)
- |> Map.put("user", user)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("user", user)
- activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_activities([user.ap_id | user.following], params)
+ |> Enum.reverse()
conn
|> add_link_headers(:home_timeline, activities)
end
def public_timeline(%{assigns: %{user: user}} = conn, params) do
- params = params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("local_only", params["local"] in [true, "True", "true", "1"])
- |> Map.put("blocking_user", user)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", params["local"] in [true, "True", "true", "1"])
+ |> Map.put("blocking_user", user)
- activities = ActivityPub.fetch_public_activities(params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_public_activities(params)
+ |> Enum.reverse()
conn
|> add_link_headers(:public_timeline, activities)
def user_statuses(%{assigns: %{user: user}} = conn, params) do
with %User{ap_id: ap_id} <- Repo.get(User, params["id"]) do
- params = params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("actor_id", ap_id)
- |> Map.put("whole_db", true)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("actor_id", ap_id)
+ |> Map.put("whole_db", true)
- activities = ActivityPub.fetch_public_activities(params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_public_activities(params)
+ |> Enum.reverse()
conn
|> add_link_headers(:user_statuses, activities, params["id"])
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Repo.get(Activity, id),
true <- ActivityPub.visible_for_user?(activity, user) do
- render conn, StatusView, "status.json", %{activity: activity, for: user}
+ render(conn, StatusView, "status.json", %{activity: activity, for: user})
end
end
def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Repo.get(Activity, id),
- activities <- ActivityPub.fetch_activities_for_context(activity.data["context"], %{"blocking_user" => user, "user" => user}),
- activities <- activities |> Enum.filter(fn (%{id: aid}) -> to_string(aid) != to_string(id) end),
- activities <- activities |> Enum.filter(fn (%{data: %{"type" => type}}) -> type == "Create" end),
- grouped_activities <- Enum.group_by(activities, fn (%{id: id}) -> id < activity.id end) do
+ activities <-
+ ActivityPub.fetch_activities_for_context(activity.data["context"], %{
+ "blocking_user" => user,
+ "user" => user
+ }),
+ activities <-
+ activities |> Enum.filter(fn %{id: aid} -> to_string(aid) != to_string(id) end),
+ activities <-
+ activities |> Enum.filter(fn %{data: %{"type" => type}} -> type == "Create" end),
+ grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
result = %{
- ancestors: StatusView.render("index.json", for: user, activities: grouped_activities[true] || [], as: :activity) |> Enum.reverse,
- descendants: StatusView.render("index.json", for: user, activities: grouped_activities[false] || [], as: :activity) |> Enum.reverse,
+ ancestors:
+ StatusView.render(
+ "index.json",
+ for: user,
+ activities: grouped_activities[true] || [],
+ as: :activity
+ )
+ |> Enum.reverse(),
+ descendants:
+ StatusView.render(
+ "index.json",
+ for: user,
+ activities: grouped_activities[false] || [],
+ as: :activity
+ )
+ |> Enum.reverse()
}
json(conn, result)
end
def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do
- params = params
- |> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
- |> Map.put("no_attachment_links", true)
+ params =
+ params
+ |> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
+ |> Map.put("no_attachment_links", true)
{:ok, activity} = CommonAPI.post(user, params)
- render conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}
+ render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
end
def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, announce, _activity} = CommonAPI.repeat(ap_id_or_id, user) do
- render conn, StatusView, "status.json", %{activity: announce, for: user, as: :activity}
+ render(conn, StatusView, "status.json", %{activity: announce, for: user, as: :activity})
end
end
def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _fav, %{data: %{"id" => id}}} = CommonAPI.favorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
- render conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}
+ render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
end
end
def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
- render conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity}
+ render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
end
end
def notifications(%{assigns: %{user: user}} = conn, params) do
notifications = Notification.for_user(user, params)
- result = Enum.map(notifications, fn x ->
- render_notification(user, x)
- end)
- |> Enum.filter(&(&1))
+
+ result =
+ Enum.map(notifications, fn x ->
+ render_notification(user, x)
+ end)
+ |> Enum.filter(& &1)
conn
|> add_link_headers(:notifications, notifications)
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
id = List.wrap(id)
- q = from u in User,
- where: u.id in ^id
+ q = from(u in User, where: u.id in ^id)
targets = Repo.all(q)
- render conn, AccountView, "relationships.json", %{user: user, targets: targets}
+ render(conn, AccountView, "relationships.json", %{user: user, targets: targets})
end
def upload(%{assigns: %{user: _}} = conn, %{"file" => file}) do
with {:ok, object} <- ActivityPub.upload(file) do
- data = object.data
- |> Map.put("id", object.id)
+ data =
+ object.data
+ |> Map.put("id", object.id)
- render conn, StatusView, "attachment.json", %{attachment: data}
+ render(conn, StatusView, "attachment.json", %{attachment: data})
end
end
def favourited_by(conn, %{"id" => id}) do
with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
- q = from u in User,
- where: u.ap_id in ^likes
+ q = from(u in User, where: u.ap_id in ^likes)
users = Repo.all(q)
- render conn, AccountView, "accounts.json", %{users: users, as: :user}
+ render(conn, AccountView, "accounts.json", %{users: users, as: :user})
else
_ -> json(conn, [])
end
def reblogged_by(conn, %{"id" => id}) do
with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
- q = from u in User,
- where: u.ap_id in ^announces
+ q = from(u in User, where: u.ap_id in ^announces)
users = Repo.all(q)
- render conn, AccountView, "accounts.json", %{users: users, as: :user}
+ render(conn, AccountView, "accounts.json", %{users: users, as: :user})
else
_ -> json(conn, [])
end
end
def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do
- params = params
- |> Map.put("type", "Create")
- |> Map.put("local_only", !!params["local"])
- |> Map.put("blocking_user", user)
+ params =
+ params
+ |> Map.put("type", "Create")
+ |> Map.put("local_only", !!params["local"])
+ |> Map.put("blocking_user", user)
- activities = ActivityPub.fetch_public_activities(params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_public_activities(params)
+ |> Enum.reverse()
conn
|> add_link_headers(:hashtag_timeline, activities, params["tag"])
def followers(conn, %{"id" => id}) do
with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_followers(user) do
- render conn, AccountView, "accounts.json", %{users: followers, as: :user}
+ render(conn, AccountView, "accounts.json", %{users: followers, as: :user})
end
end
def following(conn, %{"id" => id}) do
with %User{} = user <- Repo.get(User, id),
{:ok, followers} <- User.get_friends(user) do
- render conn, AccountView, "accounts.json", %{users: followers, as: :user}
+ render(conn, AccountView, "accounts.json", %{users: followers, as: :user})
end
end
with %User{} = followed <- Repo.get(User, id),
{:ok, follower} <- User.follow(follower, followed),
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
- render conn, AccountView, "relationship.json", %{user: follower, target: followed}
+ render(conn, AccountView, "relationship.json", %{user: follower, target: followed})
else
{:error, message} ->
conn
with %User{} = followed <- Repo.get_by(User, nickname: uri),
{:ok, follower} <- User.follow(follower, followed),
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
- render conn, AccountView, "account.json", %{user: followed}
+ render(conn, AccountView, "account.json", %{user: followed})
else
{:error, message} ->
conn
# TODO: Clean up and unify
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
with %User{} = followed <- Repo.get(User, id),
- { :ok, follower, follow_activity } <- User.unfollow(follower, followed),
- { :ok, _activity } <- ActivityPub.insert(%{
- "type" => "Undo",
- "actor" => follower.ap_id,
- "object" => follow_activity.data["id"] # get latest Follow for these users
- }) do
- render conn, AccountView, "relationship.json", %{user: follower, target: followed}
+ {:ok, follower, follow_activity} <- User.unfollow(follower, followed),
+ {:ok, _activity} <-
+ ActivityPub.insert(%{
+ "type" => "Undo",
+ "actor" => follower.ap_id,
+ # get latest Follow for these users
+ "object" => follow_activity.data["id"]
+ }) do
+ render(conn, AccountView, "relationship.json", %{user: follower, target: followed})
end
end
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
with %User{} = blocked <- Repo.get(User, id),
{:ok, blocker} <- User.block(blocker, blocked) do
- render conn, AccountView, "relationship.json", %{user: blocker, target: blocked}
+ render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked})
else
{:error, message} ->
conn
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
with %User{} = blocked <- Repo.get(User, id),
{:ok, blocker} <- User.unblock(blocker, blocked) do
- render conn, AccountView, "relationship.json", %{user: blocker, target: blocked}
+ render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked})
else
{:error, message} ->
conn
# TODO: Use proper query
def blocks(%{assigns: %{user: user}} = conn, _) do
with blocked_users <- user.info["blocks"] || [],
- accounts <- Enum.map(blocked_users, fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end) do
+ accounts <- Enum.map(blocked_users, fn ap_id -> User.get_cached_by_ap_id(ap_id) end) do
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
json(conn, res)
end
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
accounts = User.search(query, params["resolve"] == "true")
- fetched = if Regex.match?(~r/https?:/, query) do
- with {:ok, activities} <- OStatus.fetch_activity_from_url(query) do
- activities
- else
- _e -> []
- end
- end || []
+ fetched =
+ if Regex.match?(~r/https?:/, query) do
+ with {:ok, activities} <- OStatus.fetch_activity_from_url(query) do
+ activities
+ else
+ _e -> []
+ end
+ end || []
+
+ q =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = 'Create'", a.data),
+ where:
+ fragment(
+ "to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)",
+ a.data,
+ ^query
+ ),
+ limit: 20
+ )
- q = from a in Activity,
- where: fragment("?->>'type' = 'Create'", a.data),
- where: fragment("to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)", a.data, ^query),
- limit: 20
statuses = Repo.all(q) ++ fetched
res = %{
"accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
- "statuses" => StatusView.render("index.json", activities: statuses, for: user, as: :activity),
+ "statuses" =>
+ StatusView.render("index.json", activities: statuses, for: user, as: :activity),
"hashtags" => []
}
end
def favourites(%{assigns: %{user: user}} = conn, _) do
- params = %{}
- |> Map.put("type", "Create")
- |> Map.put("favorited_by", user.ap_id)
- |> Map.put("blocking_user", user)
+ params =
+ %{}
+ |> Map.put("type", "Create")
+ |> Map.put("favorited_by", user.ap_id)
+ |> Map.put("blocking_user", user)
- activities = ActivityPub.fetch_public_activities(params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_public_activities(params)
+ |> Enum.reverse()
conn
|> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
end
def index(%{assigns: %{user: user}} = conn, _params) do
- token = conn
- |> get_session(:oauth_token)
+ token =
+ conn
+ |> get_session(:oauth_token)
if user && token do
mastodon_emoji = mastodonized_emoji()
accounts = Map.put(%{}, user.id, AccountView.render("account.json", %{user: user}))
- initial_state = %{
- meta: %{
- streaming_api_base_url: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"),
- access_token: token,
- locale: "en",
- domain: Pleroma.Web.Endpoint.host(),
- admin: "1",
- me: "#{user.id}",
- unfollow_modal: false,
- boost_modal: false,
- delete_modal: true,
- auto_play_gif: false,
- reduce_motion: false
- },
- compose: %{
- me: "#{user.id}",
- default_privacy: "public",
- default_sensitive: false
- },
- media_attachments: %{
- accept_content_types: [
- ".jpg",
- ".jpeg",
- ".png",
- ".gif",
- ".webm",
- ".mp4",
- ".m4v",
- "image\/jpeg",
- "image\/png",
- "image\/gif",
- "video\/webm",
- "video\/mp4"
- ]
- },
- settings: %{
- onboarded: true,
- home: %{
- shows: %{
- reblog: true,
- reply: true
- }
+
+ initial_state =
+ %{
+ meta: %{
+ streaming_api_base_url:
+ String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"),
+ access_token: token,
+ locale: "en",
+ domain: Pleroma.Web.Endpoint.host(),
+ admin: "1",
+ me: "#{user.id}",
+ unfollow_modal: false,
+ boost_modal: false,
+ delete_modal: true,
+ auto_play_gif: false,
+ reduce_motion: false
},
- notifications: %{
- alerts: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
- },
- shows: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
+ compose: %{
+ me: "#{user.id}",
+ default_privacy: "public",
+ default_sensitive: false
+ },
+ media_attachments: %{
+ accept_content_types: [
+ ".jpg",
+ ".jpeg",
+ ".png",
+ ".gif",
+ ".webm",
+ ".mp4",
+ ".m4v",
+ "image\/jpeg",
+ "image\/png",
+ "image\/gif",
+ "video\/webm",
+ "video\/mp4"
+ ]
+ },
+ settings: %{
+ onboarded: true,
+ home: %{
+ shows: %{
+ reblog: true,
+ reply: true
+ }
},
- sounds: %{
- follow: true,
- favourite: true,
- reblog: true,
- mention: true
+ notifications: %{
+ alerts: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ },
+ shows: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ },
+ sounds: %{
+ follow: true,
+ favourite: true,
+ reblog: true,
+ mention: true
+ }
}
- }
- },
- push_subscription: nil,
- accounts: accounts,
- custom_emojis: mastodon_emoji,
- char_limit: Keyword.get(@instance, :limit)
- } |> Jason.encode!
+ },
+ push_subscription: nil,
+ accounts: accounts,
+ custom_emojis: mastodon_emoji,
+ char_limit: Keyword.get(@instance, :limit)
+ }
+ |> Jason.encode!()
+
conn
|> put_layout(false)
|> render(MastodonView, "index.html", %{initial_state: initial_state})
{:ok, app}
else
_e ->
- cs = App.register_changeset(%App{}, %{client_name: "Mastodon-Local", redirect_uris: ".", scopes: "read,write,follow"})
+ cs =
+ App.register_changeset(%App{}, %{
+ client_name: "Mastodon-Local",
+ redirect_uris: ".",
+ scopes: "read,write,follow"
+ })
+
Repo.insert(cs)
end
end
- def login_post(conn, %{"authorization" => %{ "name" => name, "password" => password}}) do
+ def login_post(conn, %{"authorization" => %{"name" => name, "password" => password}}) do
with %User{} = user <- User.get_cached_by_nickname(name),
true <- Pbkdf2.checkpw(password, user.password_hash),
{:ok, app} <- get_or_make_app(),
def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Logger.debug("Unimplemented, returning unmodified relationship")
+
with %User{} = target <- Repo.get(User, id) do
- render conn, AccountView, "relationship.json", %{user: user, target: target}
+ render(conn, AccountView, "relationship.json", %{user: user, target: target})
end
end
def render_notification(user, %{id: id, activity: activity, inserted_at: created_at} = _params) do
actor = User.get_cached_by_ap_id(activity.data["actor"])
- created_at = NaiveDateTime.to_iso8601(created_at)
- |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
+
+ created_at =
+ NaiveDateTime.to_iso8601(created_at)
+ |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
+
case activity.data["type"] do
"Create" ->
- %{id: id, type: "mention", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: activity, for: user})}
+ %{
+ id: id,
+ type: "mention",
+ created_at: created_at,
+ account: AccountView.render("account.json", %{user: actor}),
+ status: StatusView.render("status.json", %{activity: activity, for: user})
+ }
+
"Like" ->
liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
- %{id: id, type: "favourite", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: liked_activity, for: user})}
+
+ %{
+ id: id,
+ type: "favourite",
+ created_at: created_at,
+ account: AccountView.render("account.json", %{user: actor}),
+ status: StatusView.render("status.json", %{activity: liked_activity, for: user})
+ }
+
"Announce" ->
announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
- %{id: id, type: "reblog", created_at: created_at, account: AccountView.render("account.json", %{user: actor}), status: StatusView.render("status.json", %{activity: announced_activity, for: user})}
+
+ %{
+ id: id,
+ type: "reblog",
+ created_at: created_at,
+ account: AccountView.render("account.json", %{user: actor}),
+ status: StatusView.render("status.json", %{activity: announced_activity, for: user})
+ }
+
"Follow" ->
- %{id: id, type: "follow", created_at: created_at, account: AccountView.render("account.json", %{user: actor})}
- _ -> nil
+ %{
+ id: id,
+ type: "follow",
+ created_at: created_at,
+ account: AccountView.render("account.json", %{user: actor})
+ }
+
+ _ ->
+ nil
end
end
end
alias Pleroma.Web.OAuth.Token
alias Pleroma.{User, Repo}
- transport :streaming, Phoenix.Transports.WebSocket.Raw,
- timeout: :infinity # We never receive data.
+ transport(
+ :streaming,
+ Phoenix.Transports.WebSocket.Raw,
+ # We never receive data.
+ timeout: :infinity
+ )
def connect(params, socket) do
with token when not is_nil(token) <- params["access_token"],
%Token{user_id: user_id} <- Repo.get_by(Token, token: token),
%User{} = user <- Repo.get(User, user_id),
stream when stream in ["public", "public:local", "user"] <- params["stream"] do
- socket = socket
- |> assign(:topic, params["stream"])
- |> assign(:user, user)
+ socket =
+ socket
+ |> assign(:topic, params["stream"])
+ |> assign(:user, user)
+
Pleroma.Web.Streamer.add_socket(params["stream"], socket)
{:ok, socket}
else
def id(_), do: nil
def handle(:text, message, _state) do
- #| :ok
- #| state
- #| {:text, message}
- #| {:text, message, state}
- #| {:close, "Goodbye!"}
+ # | :ok
+ # | state
+ # | {:text, message}
+ # | {:text, message, state}
+ # | {:close, "Goodbye!"}
{:text, message}
end
defp get_replied_to_activities(activities) do
activities
|> Enum.map(fn
- (%{data: %{"type" => "Create", "object" => %{"inReplyTo" => inReplyTo}}}) ->
- (inReplyTo != "") && inReplyTo
- _ -> nil
+ %{data: %{"type" => "Create", "object" => %{"inReplyTo" => inReplyTo}}} ->
+ inReplyTo != "" && inReplyTo
+
+ _ ->
+ nil
end)
- |> Enum.filter(&(&1))
+ |> Enum.filter(& &1)
|> Activity.create_activity_by_object_id_query()
- |> Repo.all
- |> Enum.reduce(%{}, fn(activity, acc) -> Map.put(acc,activity.data["object"]["id"], activity) end)
+ |> Repo.all()
+ |> Enum.reduce(%{}, fn activity, acc ->
+ Map.put(acc, activity.data["object"]["id"], activity)
+ end)
end
def render("index.json", opts) do
replied_to_activities = get_replied_to_activities(opts.activities)
- render_many(opts.activities, StatusView, "status.json", Map.put(opts, :replied_to_activities, replied_to_activities))
+
+ render_many(
+ opts.activities,
+ StatusView,
+ "status.json",
+ Map.put(opts, :replied_to_activities, replied_to_activities)
+ )
end
- def render("status.json", %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts) do
+ def render(
+ "status.json",
+ %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts
+ ) do
user = User.get_cached_by_ap_id(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"])
reblogged = Activity.get_create_activity_by_object_ap_id(object)
reblogged = render("status.json", Map.put(opts, :activity, reblogged))
- mentions = activity.recipients
- |> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn (user) -> AccountView.render("mention.json", %{user: user}) end)
+ mentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
%{
id: to_string(activity.id),
uri: object,
- url: nil, # TODO: This might be wrong, check with mastodon.
+ # TODO: This might be wrong, check with mastodon.
+ url: nil,
account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
tags = object["tag"] || []
sensitive = object["sensitive"] || Enum.member?(tags, "nsfw")
- mentions = activity.recipients
- |> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn (user) -> AccountView.render("mention.json", %{user: user}) end)
+ mentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
- attachments = render_many(object["attachment"] || [], StatusView, "attachment.json", as: :attachment)
+ attachments =
+ render_many(object["attachment"] || [], StatusView, "attachment.json", as: :attachment)
created_at = Utils.to_masto_date(object["published"])
reply_to = get_reply_to(activity, opts)
reply_to_user = reply_to && User.get_cached_by_ap_id(reply_to.data["actor"])
- emojis = (activity.data["object"]["emoji"] || [])
- |> Enum.map(fn {name, url} ->
- name = HtmlSanitizeEx.strip_tags(name)
- url = HtmlSanitizeEx.strip_tags(url)
- %{ shortcode: name, url: url, static_url: url }
- end)
+ emojis =
+ (activity.data["object"]["emoji"] || [])
+ |> Enum.map(fn {name, url} ->
+ name = HtmlSanitizeEx.strip_tags(name)
+ url = HtmlSanitizeEx.strip_tags(url)
+ %{shortcode: name, url: url, static_url: url}
+ end)
%{
id: to_string(activity.id),
visibility: get_visibility(object),
media_attachments: attachments |> Enum.take(4),
mentions: mentions,
- tags: [], # fix,
+ # fix,
+ tags: [],
application: %{
name: "Web",
website: nil
public = "https://www.w3.org/ns/activitystreams#Public"
to = object["to"] || []
cc = object["cc"] || []
+
cond do
public in to -> "public"
public in cc -> "unlisted"
- Enum.any?(to, &(String.contains?(&1, "/followers"))) -> "private"
+ Enum.any?(to, &String.contains?(&1, "/followers")) -> "private"
true -> "direct"
end
end
def render("attachment.json", %{attachment: attachment}) do
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
- type = cond do
- String.contains?(media_type, "image") -> "image"
- String.contains?(media_type, "video") -> "video"
- String.contains?(media_type, "audio") -> "audio"
- true -> "unknown"
- end
+ type =
+ cond do
+ String.contains?(media_type, "image") -> "image"
+ String.contains?(media_type, "video") -> "video"
+ String.contains?(media_type, "audio") -> "audio"
+ true -> "unknown"
+ end
- << hash_id::signed-32, _rest::binary >> = :crypto.hash(:md5, href)
+ <<hash_id::signed-32, _rest::binary>> = :crypto.hash(:md5, href)
%{
id: to_string(attachment["id"] || hash_id),
@httpoison Application.get_env(:pleroma, :httpoison)
- @max_body_length 25 * 1048576
+ @max_body_length 25 * 1_048_576
@cache_control %{
default: "public, max-age=1209600",
- error: "public, must-revalidate, max-age=160",
+ error: "public, must-revalidate, max-age=160"
}
def remote(conn, %{"sig" => sig, "url" => url}) do
config = Application.get_env(:pleroma, :media_proxy, [])
- with \
- true <- Keyword.get(config, :enabled, false),
- {:ok, url} <- Pleroma.Web.MediaProxy.decode_url(sig, url),
- {:ok, content_type, body} <- proxy_request(url)
- do
+
+ with true <- Keyword.get(config, :enabled, false),
+ {:ok, url} <- Pleroma.Web.MediaProxy.decode_url(sig, url),
+ {:ok, content_type, body} <- proxy_request(url) do
conn
|> put_resp_content_type(content_type)
|> set_cache_header(:default)
|> send_resp(200, body)
else
- false -> send_error(conn, 404)
- {:error, :invalid_signature} -> send_error(conn, 403)
- {:error, {:http, _, url}} -> redirect_or_error(conn, url, Keyword.get(config, :redirect_on_failure, true))
+ false ->
+ send_error(conn, 404)
+
+ {:error, :invalid_signature} ->
+ send_error(conn, 403)
+
+ {:error, {:http, _, url}} ->
+ redirect_or_error(conn, url, Keyword.get(config, :redirect_on_failure, true))
end
end
defp proxy_request(link) do
- headers = [{"user-agent", "Pleroma/MediaProxy; #{Pleroma.Web.base_url()} <#{Application.get_env(:pleroma, :instance)[:email]}>"}]
- options = @httpoison.process_request_options([:insecure, {:follow_redirect, true}]) ++ [{:pool, :default}]
- with \
- {:ok, 200, headers, client} <- :hackney.request(:get, link, headers, "", options),
- headers = Enum.into(headers, Map.new),
- {:ok, body} <- proxy_request_body(client),
- content_type <- proxy_request_content_type(headers, body)
- do
+ headers = [
+ {"user-agent",
+ "Pleroma/MediaProxy; #{Pleroma.Web.base_url()} <#{
+ Application.get_env(:pleroma, :instance)[:email]
+ }>"}
+ ]
+
+ options =
+ @httpoison.process_request_options([:insecure, {:follow_redirect, true}]) ++
+ [{:pool, :default}]
+
+ with {:ok, 200, headers, client} <- :hackney.request(:get, link, headers, "", options),
+ headers = Enum.into(headers, Map.new()),
+ {:ok, body} <- proxy_request_body(client),
+ content_type <- proxy_request_content_type(headers, body) do
{:ok, content_type, body}
else
{:ok, status, _, _} ->
- Logger.warn "MediaProxy: request failed, status #{status}, link: #{link}"
+ Logger.warn("MediaProxy: request failed, status #{status}, link: #{link}")
{:error, {:http, :bad_status, link}}
+
{:error, error} ->
- Logger.warn "MediaProxy: request failed, error #{inspect error}, link: #{link}"
+ Logger.warn("MediaProxy: request failed, error #{inspect(error)}, link: #{link}")
{:error, {:http, error, link}}
end
end
end
defp proxy_request_body(client), do: proxy_request_body(client, <<>>)
+
defp proxy_request_body(client, body) when byte_size(body) < @max_body_length do
case :hackney.stream_body(client) do
- {:ok, data} -> proxy_request_body(client, <<body :: binary, data :: binary>>)
+ {:ok, data} -> proxy_request_body(client, <<body::binary, data::binary>>)
:done -> {:ok, body}
{:error, reason} -> {:error, reason}
end
end
+
defp proxy_request_body(client, _) do
:hackney.close(client)
{:error, :body_too_large}
defp proxy_request_content_type(headers, _body) do
headers["Content-Type"] || headers["content-type"] || "image/jpeg"
end
-
end
def url(url) do
config = Application.get_env(:pleroma, :media_proxy, [])
- if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url) do
+
+ if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) do
url
else
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
base64 = Base.url_encode64(url, @base64_opts)
sig = :crypto.hmac(:sha, secret, base64)
sig64 = sig |> Base.url_encode64(@base64_opts)
- Keyword.get(config, :base_url, Pleroma.Web.base_url) <> "/proxy/#{sig64}/#{base64}"
+ Keyword.get(config, :base_url, Pleroma.Web.base_url()) <> "/proxy/#{sig64}/#{base64}"
end
end
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
sig = Base.url_decode64!(sig, @base64_opts)
local_sig = :crypto.hmac(:sha, secret, url)
+
if local_sig == sig do
{:ok, Base.url_decode64!(url, @base64_opts)}
else
{:error, :invalid_signature}
end
end
-
end
import Ecto.{Changeset}
schema "apps" do
- field :client_name, :string
- field :redirect_uris, :string
- field :scopes, :string
- field :website, :string
- field :client_id, :string
- field :client_secret, :string
+ field(:client_name, :string)
+ field(:redirect_uris, :string)
+ field(:scopes, :string)
+ field(:website, :string)
+ field(:client_id, :string)
+ field(:client_secret, :string)
timestamps()
end
def register_changeset(struct, params \\ %{}) do
- changeset = struct
- |> cast(params, [:client_name, :redirect_uris, :scopes, :website])
- |> validate_required([:client_name, :redirect_uris, :scopes])
+ changeset =
+ struct
+ |> cast(params, [:client_name, :redirect_uris, :scopes, :website])
+ |> validate_required([:client_name, :redirect_uris, :scopes])
if changeset.valid? do
changeset
- |> put_change(:client_id, :crypto.strong_rand_bytes(32) |> Base.url_encode64)
- |> put_change(:client_secret, :crypto.strong_rand_bytes(32) |> Base.url_encode64)
+ |> put_change(:client_id, :crypto.strong_rand_bytes(32) |> Base.url_encode64())
+ |> put_change(:client_secret, :crypto.strong_rand_bytes(32) |> Base.url_encode64())
else
changeset
end
import Ecto.{Changeset}
schema "oauth_authorizations" do
- field :token, :string
- field :valid_until, :naive_datetime
- field :used, :boolean, default: false
- belongs_to :user, Pleroma.User
- belongs_to :app, Pleroma.App
+ field(:token, :string)
+ field(:valid_until, :naive_datetime)
+ field(:used, :boolean, default: false)
+ belongs_to(:user, Pleroma.User)
+ belongs_to(:app, Pleroma.App)
timestamps()
end
def create_authorization(%App{} = app, %User{} = user) do
- token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+ token = :crypto.strong_rand_bytes(32) |> Base.url_encode64()
authorization = %Authorization{
token: token,
used: false,
user_id: user.id,
app_id: app.id,
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 60 * 10)
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)
}
Repo.insert(authorization)
end
def use_token(%Authorization{used: false, valid_until: valid_until} = auth) do
- if NaiveDateTime.diff(NaiveDateTime.utc_now, valid_until) < 0 do
+ if NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) < 0 do
Repo.update(use_changeset(auth, %{used: true}))
else
{:error, "token expired"}
end
end
+
def use_token(%Authorization{used: true}), do: {:error, "already used"}
end
defmodule Pleroma.Web.OAuth.FallbackController do
- use Pleroma.Web, :controller
- alias Pleroma.Web.OAuth.OAuthController
+ use Pleroma.Web, :controller
+ alias Pleroma.Web.OAuth.OAuthController
- # No user/password
- def call(conn, _) do
- conn
- |> put_flash(:error, "Invalid Username/Password")
- |> OAuthController.authorize(conn.params)
- end
-
-end
\ No newline at end of file
+ # No user/password
+ def call(conn, _) do
+ conn
+ |> put_flash(:error, "Invalid Username/Password")
+ |> OAuthController.authorize(conn.params)
+ end
+end
alias Pleroma.{Repo, User}
alias Comeonin.Pbkdf2
- plug :fetch_session
- plug :fetch_flash
+ plug(:fetch_session)
+ plug(:fetch_flash)
- action_fallback Pleroma.Web.OAuth.FallbackController
+ action_fallback(Pleroma.Web.OAuth.FallbackController)
def authorize(conn, params) do
- render conn, "show.html", %{
+ render(conn, "show.html", %{
response_type: params["response_type"],
client_id: params["client_id"],
scope: params["scope"],
redirect_uri: params["redirect_uri"],
state: params["state"]
- }
+ })
end
- def create_authorization(conn, %{"authorization" => %{"name" => name, "password" => password, "client_id" => client_id, "redirect_uri" => redirect_uri} = params}) do
+ def create_authorization(conn, %{
+ "authorization" =>
+ %{
+ "name" => name,
+ "password" => password,
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri
+ } = params
+ }) do
with %User{} = user <- User.get_cached_by_nickname(name),
true <- Pbkdf2.checkpw(password, user.password_hash),
%App{} = app <- Repo.get_by(App, client_id: client_id),
{:ok, auth} <- Authorization.create_authorization(app, user) do
if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do
- render conn, "results.html", %{
+ render(conn, "results.html", %{
auth: auth
- }
+ })
else
connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?"
url = "#{redirect_uri}#{connector}code=#{auth.token}"
- url = if params["state"] do
- url <> "&state=#{params["state"]}"
- else
- url
- end
+
+ url =
+ if params["state"] do
+ url <> "&state=#{params["state"]}"
+ else
+ url
+ end
+
redirect(conn, external: url)
end
end
# TODO
# - proper scope handling
def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
- with %App{} = app <- Repo.get_by(App, client_id: params["client_id"], client_secret: params["client_secret"]),
+ with %App{} = app <-
+ Repo.get_by(
+ App,
+ client_id: params["client_id"],
+ client_secret: params["client_secret"]
+ ),
fixed_token = fix_padding(params["code"]),
%Authorization{} = auth <- Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
{:ok, token} <- Token.exchange_token(app, auth) do
expires_in: 60 * 10,
scope: "read write follow"
}
+
json(conn, response)
else
_error -> json(conn, %{error: "Invalid credentials"})
# TODO
# - investigate a way to verify the user wants to grant read/write/follow once scope handling is done
- def token_exchange(conn, %{"grant_type" => "password", "name" => name, "password" => password} = params) do
- with %App{} = app <- Repo.get_by(App, client_id: params["client_id"], client_secret: params["client_secret"]),
+ def token_exchange(
+ conn,
+ %{"grant_type" => "password", "name" => name, "password" => password} = params
+ ) do
+ with %App{} = app <-
+ Repo.get_by(
+ App,
+ client_id: params["client_id"],
+ client_secret: params["client_secret"]
+ ),
%User{} = user <- User.get_cached_by_nickname(name),
true <- Pbkdf2.checkpw(password, user.password_hash),
{:ok, auth} <- Authorization.create_authorization(app, user),
expires_in: 60 * 10,
scope: "read write follow"
}
+
json(conn, response)
else
_error -> json(conn, %{error: "Invalid credentials"})
defp fix_padding(token) do
token
|> Base.url_decode64!(padding: false)
- |> Base.url_encode64
+ |> Base.url_encode64()
end
end
alias Pleroma.Web.OAuth.{Token, App, Authorization}
schema "oauth_tokens" do
- field :token, :string
- field :refresh_token, :string
- field :valid_until, :naive_datetime
- belongs_to :user, Pleroma.User
- belongs_to :app, Pleroma.App
+ field(:token, :string)
+ field(:refresh_token, :string)
+ field(:valid_until, :naive_datetime)
+ belongs_to(:user, Pleroma.User)
+ belongs_to(:app, Pleroma.App)
timestamps()
end
end
def create_token(%App{} = app, %User{} = user) do
- token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
- refresh_token = :crypto.strong_rand_bytes(32) |> Base.url_encode64
+ token = :crypto.strong_rand_bytes(32) |> Base.url_encode64()
+ refresh_token = :crypto.strong_rand_bytes(32) |> Base.url_encode64()
token = %Token{
token: token,
refresh_token: refresh_token,
user_id: user.id,
app_id: app.id,
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 60 * 10)
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)
}
Repo.insert(token)
require Logger
defp get_href(id) do
- with %Object{data: %{ "external_url" => external_url } }<- Object.get_cached_by_ap_id(id) do
+ with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
external_url
else
_e -> id
end
defp get_in_reply_to(%{"object" => %{"inReplyTo" => in_reply_to}}) do
- [{:"thr:in-reply-to", [ref: to_charlist(in_reply_to), href: to_charlist(get_href(in_reply_to))], []}]
+ [
+ {:"thr:in-reply-to",
+ [ref: to_charlist(in_reply_to), href: to_charlist(get_href(in_reply_to))], []}
+ ]
end
defp get_in_reply_to(_), do: []
defp get_mentions(to) do
- Enum.map(to, fn (id) ->
+ Enum.map(to, fn id ->
cond do
# Special handling for the AP/Ostatus public collections
"https://www.w3.org/ns/activitystreams#Public" == id ->
- {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection", href: "http://activityschema.org/collection/public"], []}
+ {:link,
+ [
+ rel: "mentioned",
+ "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection",
+ href: "http://activityschema.org/collection/public"
+ ], []}
+
# Ostatus doesn't handle follower collections, ignore these.
- Regex.match?(~r/^#{Pleroma.Web.base_url}.+followers$/, id) ->
+ Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) ->
[]
+
true ->
- {:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person", href: id], []}
+ {:link,
+ [
+ rel: "mentioned",
+ "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person",
+ href: id
+ ], []}
end
end)
end
defp get_links(%{local: true, data: data}) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
+
[
{:link, [type: ['application/atom+xml'], href: h.(data["object"]["id"]), rel: 'self'], []},
{:link, [type: ['text/html'], href: h.(data["object"]["id"]), rel: 'alternate'], []}
]
end
- defp get_links(%{local: false,
- data: %{
- "object" => %{
- "external_url" => external_url
- }
- }}) do
+ defp get_links(%{
+ local: false,
+ data: %{
+ "object" => %{
+ "external_url" => external_url
+ }
+ }
+ }) do
+ h = fn str -> [to_charlist(str)] end
- h = fn(str) -> [to_charlist(str)] end
[
{:link, [type: ['text/html'], href: h.(external_url), rel: 'alternate'], []}
]
defp get_links(_activity), do: []
defp get_emoji_links(emojis) do
- Enum.map(emojis, fn({emoji, file}) ->
+ Enum.map(emojis, fn {emoji, file} ->
{:link, [name: to_charlist(emoji), rel: 'emoji', href: to_charlist(file)], []}
end)
end
def to_simple_form(activity, user, with_author \\ false)
+
def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["object"]["published"]
inserted_at = activity.data["object"]["published"]
- attachments = Enum.map(activity.data["object"]["attachment"] || [], fn(attachment) ->
- url = hd(attachment["url"])
- {:link, [rel: 'enclosure', href: to_charlist(url["href"]), type: to_charlist(url["mediaType"])], []}
- end)
+ attachments =
+ Enum.map(activity.data["object"]["attachment"] || [], fn attachment ->
+ url = hd(attachment["url"])
+
+ {:link,
+ [rel: 'enclosure', href: to_charlist(url["href"]), type: to_charlist(url["mediaType"])],
+ []}
+ end)
in_reply_to = get_in_reply_to(activity.data)
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
mentions = activity.recipients |> get_mentions
- categories = (activity.data["object"]["tag"] || [])
- |> Enum.map(fn (tag) ->
- if is_binary(tag) do
- {:category, [term: to_charlist(tag)], []}
- else
- nil
- end
- end)
- |> Enum.filter(&(&1))
+ categories =
+ (activity.data["object"]["tag"] || [])
+ |> Enum.map(fn tag ->
+ if is_binary(tag) do
+ {:category, [term: to_charlist(tag)], []}
+ else
+ nil
+ end
+ end)
+ |> Enum.filter(& &1)
emoji_links = get_emoji_links(activity.data["object"]["emoji"] || %{})
- summary = if activity.data["object"]["summary"] do
- [{:summary, [], h.(activity.data["object"]["summary"])}]
- else
- []
- end
+ summary =
+ if activity.data["object"]["summary"] do
+ [{:summary, [], h.(activity.data["object"]["summary"])}]
+ else
+ []
+ end
[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']},
- {:id, h.(activity.data["object"]["id"])}, # For notes, federate the object id.
+ # For notes, federate the object id.
+ {:id, h.(activity.data["object"]["id"])},
{:title, ['New note by #{user.nickname}']},
- {:content, [type: 'html'], h.(activity.data["object"]["content"] |> String.replace(~r/[\n\r]/, ""))},
+ {:content, [type: 'html'],
+ h.(activity.data["object"]["content"] |> String.replace(~r/[\n\r]/, ""))},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
{:"ostatus:conversation", [ref: h.(activity.data["context"])], h.(activity.data["context"])},
- {:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
- ] ++ summary ++ get_links(activity) ++ categories ++ attachments ++ in_reply_to ++ author ++ mentions ++ emoji_links
+ {:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []}
+ ] ++
+ summary ++
+ get_links(activity) ++
+ categories ++ attachments ++ in_reply_to ++ author ++ mentions ++ emoji_links
end
def to_simple_form(%{data: %{"type" => "Like"}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["published"]
inserted_at = activity.data["published"]
{:content, [type: 'html'], ['#{user.nickname} favorited something']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
- {:"activity:object", [
- {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
- {:id, h.(activity.data["object"])}, # For notes, federate the object id.
- ]},
+ {:"activity:object",
+ [
+ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
+ # For notes, federate the object id.
+ {:id, h.(activity.data["object"])}
+ ]},
{:"ostatus:conversation", [ref: h.(activity.data["context"])], h.(activity.data["context"])},
{:link, [ref: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
{:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
end
def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["published"]
inserted_at = activity.data["published"]
retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true)
mentions = activity.recipients |> get_mentions
+
[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']},
end
def to_simple_form(%{data: %{"type" => "Follow"}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["published"]
inserted_at = activity.data["published"]
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
mentions = (activity.recipients || []) |> get_mentions
+
[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/follow']},
{:id, h.(activity.data["id"])},
{:title, ['#{user.nickname} started following #{activity.data["object"]}']},
- {:content, [type: 'html'], ['#{user.nickname} started following #{activity.data["object"]}']},
+ {:content, [type: 'html'],
+ ['#{user.nickname} started following #{activity.data["object"]}']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
- {:"activity:object", [
- {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
- {:id, h.(activity.data["object"])},
- {:uri, h.(activity.data["object"])},
- ]},
- {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
+ {:"activity:object",
+ [
+ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
+ {:id, h.(activity.data["object"])},
+ {:uri, h.(activity.data["object"])}
+ ]},
+ {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
] ++ mentions ++ author
end
# Only undos of follow for now. Will need to get redone once there are more
def to_simple_form(%{data: %{"type" => "Undo"}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["published"]
inserted_at = activity.data["published"]
follow_activity = Activity.get_by_ap_id(activity.data["object"])
mentions = (activity.recipients || []) |> get_mentions
+
[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
{:id, h.(activity.data["id"])},
{:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
- {:content, [type: 'html'], ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
+ {:content, [type: 'html'],
+ ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
- {:"activity:object", [
- {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
- {:id, h.(follow_activity.data["object"])},
- {:uri, h.(follow_activity.data["object"])},
- ]},
- {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
+ {:"activity:object",
+ [
+ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
+ {:id, h.(follow_activity.data["object"])},
+ {:uri, h.(follow_activity.data["object"])}
+ ]},
+ {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
] ++ mentions ++ author
end
def to_simple_form(%{data: %{"type" => "Delete"}} = activity, user, with_author) do
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
updated_at = activity.data["published"]
inserted_at = activity.data["published"]
{:content, [type: 'html'], ['An object was deleted']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)}
- ] ++ author
+ ] ++ author
end
def to_simple_form(_, _, _), do: nil
def wrap_with_entry(simple_form) do
- [{
- :entry, [
- xmlns: 'http://www.w3.org/2005/Atom',
- "xmlns:thr": 'http://purl.org/syndication/thread/1.0',
- "xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
- "xmlns:poco": 'http://portablecontacts.net/spec/1.0',
- "xmlns:ostatus": 'http://ostatus.org/schema/1.0'
- ], simple_form
- }]
+ [
+ {
+ :entry,
+ [
+ xmlns: 'http://www.w3.org/2005/Atom',
+ "xmlns:thr": 'http://purl.org/syndication/thread/1.0',
+ "xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
+ "xmlns:poco": 'http://portablecontacts.net/spec/1.0',
+ "xmlns:ostatus": 'http://ostatus.org/schema/1.0'
+ ],
+ simple_form
+ }
+ ]
end
end
alias Pleroma.Web.MediaProxy
def to_simple_form(user, activities, _users) do
- most_recent_update = (List.first(activities) || user).updated_at
- |> NaiveDateTime.to_iso8601
+ most_recent_update =
+ (List.first(activities) || user).updated_at
+ |> NaiveDateTime.to_iso8601()
- h = fn(str) -> [to_charlist(str)] end
+ h = fn str -> [to_charlist(str)] end
last_activity = List.last(activities)
- entries = activities
- |> Enum.map(fn(activity) ->
- {:entry, ActivityRepresenter.to_simple_form(activity, user)}
- end)
- |> Enum.filter(fn ({_, form}) -> form end)
+ entries =
+ activities
+ |> Enum.map(fn activity ->
+ {:entry, ActivityRepresenter.to_simple_form(activity, user)}
+ end)
+ |> Enum.filter(fn {_, form} -> form end)
- [{
- :feed, [
- xmlns: 'http://www.w3.org/2005/Atom',
- "xmlns:thr": 'http://purl.org/syndication/thread/1.0',
- "xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
- "xmlns:poco": 'http://portablecontacts.net/spec/1.0',
- "xmlns:ostatus": 'http://ostatus.org/schema/1.0'
- ], [
- {:id, h.(OStatus.feed_path(user))},
- {:title, ['#{user.nickname}\'s timeline']},
- {:updated, h.(most_recent_update)},
- {:logo, [to_charlist(User.avatar_url(user) |> MediaProxy.url())]},
- {:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []},
- {:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []},
- {:link, [rel: 'self', href: h.(OStatus.feed_path(user)), type: 'application/atom+xml'], []},
- {:author, UserRepresenter.to_simple_form(user)},
- ] ++
- if last_activity do
- [{:link, [rel: 'next',
- href: to_charlist(OStatus.feed_path(user)) ++ '?max_id=' ++ to_charlist(last_activity.id),
- type: 'application/atom+xml'], []}]
- else
- []
- end
- ++ entries
- }]
+ [
+ {
+ :feed,
+ [
+ xmlns: 'http://www.w3.org/2005/Atom',
+ "xmlns:thr": 'http://purl.org/syndication/thread/1.0',
+ "xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
+ "xmlns:poco": 'http://portablecontacts.net/spec/1.0',
+ "xmlns:ostatus": 'http://ostatus.org/schema/1.0'
+ ],
+ [
+ {:id, h.(OStatus.feed_path(user))},
+ {:title, ['#{user.nickname}\'s timeline']},
+ {:updated, h.(most_recent_update)},
+ {:logo, [to_charlist(User.avatar_url(user) |> MediaProxy.url())]},
+ {:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []},
+ {:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []},
+ {:link, [rel: 'self', href: h.(OStatus.feed_path(user)), type: 'application/atom+xml'],
+ []},
+ {:author, UserRepresenter.to_simple_form(user)}
+ ] ++
+ if last_activity do
+ [
+ {:link,
+ [
+ rel: 'next',
+ href:
+ to_charlist(OStatus.feed_path(user)) ++
+ '?max_id=' ++ to_charlist(last_activity.id),
+ type: 'application/atom+xml'
+ ], []}
+ ]
+ else
+ []
+ end ++ entries
+ }
+ ]
end
end
def handle(entry, doc) do
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry),
- followed_uri when not is_nil(followed_uri) <- XML.string_from_xpath("/entry/activity:object/id", entry),
+ followed_uri when not is_nil(followed_uri) <-
+ XML.string_from_xpath("/entry/activity:object/id", entry),
{:ok, followed} <- OStatus.find_or_make_user(followed_uri),
{:ok, activity} <- ActivityPub.follow(actor, followed, id, false) do
User.follow(actor, followed)
3. A newly generated context id.
"""
def get_context(entry, inReplyTo) do
- context = (
- XML.string_from_xpath("//ostatus:conversation[1]", entry)
- || XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry)
- || "") |> String.trim
+ context =
+ (XML.string_from_xpath("//ostatus:conversation[1]", entry) ||
+ XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry) || "")
+ |> String.trim()
with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do
context
- else _e ->
- if String.length(context) > 0 do
- context
- else
- Utils.generate_context_id
- end
+ else
+ _e ->
+ if String.length(context) > 0 do
+ context
+ else
+ Utils.generate_context_id()
+ end
end
end
def get_people_mentions(entry) do
- :xmerl_xpath.string('//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', entry)
- |> Enum.map(fn(person) -> XML.string_from_xpath("@href", person) end)
+ :xmerl_xpath.string(
+ '//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]',
+ entry
+ )
+ |> Enum.map(fn person -> XML.string_from_xpath("@href", person) end)
end
def get_collection_mentions(entry) do
transmogrify = fn
- ("http://activityschema.org/collection/public") ->
+ "http://activityschema.org/collection/public" ->
"https://www.w3.org/ns/activitystreams#Public"
- (group) ->
+
+ group ->
group
end
- :xmerl_xpath.string('//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/collection"]', entry)
- |> Enum.map(fn(collection) -> XML.string_from_xpath("@href", collection) |> transmogrify.() end)
+ :xmerl_xpath.string(
+ '//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/collection"]',
+ entry
+ )
+ |> Enum.map(fn collection -> XML.string_from_xpath("@href", collection) |> transmogrify.() end)
end
def get_mentions(entry) do
- (get_people_mentions(entry)
- ++ get_collection_mentions(entry))
- |> Enum.filter(&(&1))
+ (get_people_mentions(entry) ++ get_collection_mentions(entry))
+ |> Enum.filter(& &1)
end
def get_emoji(entry) do
try do
:xmerl_xpath.string('//link[@rel="emoji"]', entry)
- |> Enum.reduce(%{}, fn(emoji, acc) ->
+ |> Enum.reduce(%{}, fn emoji, acc ->
Map.put(acc, XML.string_from_xpath("@name", emoji), XML.string_from_xpath("@href", emoji))
end)
rescue
activity
else
_e ->
- with inReplyToHref when not is_nil(inReplyToHref) <- XML.string_from_xpath("//thr:in-reply-to[1]/@href", entry),
+ with inReplyToHref when not is_nil(inReplyToHref) <-
+ XML.string_from_xpath("//thr:in-reply-to[1]/@href", entry),
{:ok, [activity | _]} <- OStatus.fetch_activity_from_url(inReplyToHref) do
activity
else
date <- XML.string_from_xpath("//published", entry),
unlisted <- XML.string_from_xpath("//mastodon:scope", entry) == "unlisted",
cc <- if(unlisted, do: ["https://www.w3.org/ns/activitystreams#Public"], else: []),
- note <- CommonAPI.Utils.make_note_data(actor.ap_id, to, context, content_html, attachments, inReplyToActivity, [], cw),
+ note <-
+ CommonAPI.Utils.make_note_data(
+ actor.ap_id,
+ to,
+ context,
+ content_html,
+ attachments,
+ inReplyToActivity,
+ [],
+ cw
+ ),
note <- note |> Map.put("id", id) |> Map.put("tag", tags),
note <- note |> Map.put("published", date),
note <- note |> Map.put("emoji", get_emoji(entry)),
note <- add_external_url(note, entry),
note <- note |> Map.put("cc", cc),
# TODO: Handle this case in make_note_data
- note <- (if inReplyTo && !inReplyToActivity, do: note |> Map.put("inReplyTo", inReplyTo), else: note)
- do
- res = ActivityPub.create(%{to: to, actor: actor, context: context, object: note, published: date, local: false, additional: %{"cc" => cc}})
+ note <-
+ if(
+ inReplyTo && !inReplyToActivity,
+ do: note |> Map.put("inReplyTo", inReplyTo),
+ else: note
+ ) do
+ res =
+ ActivityPub.create(%{
+ to: to,
+ actor: actor,
+ context: context,
+ object: note,
+ published: date,
+ local: false,
+ additional: %{"cc" => cc}
+ })
+
User.increase_note_count(actor)
res
else
end
def pubsub_path(user) do
- "#{Web.base_url}/push/hub/#{user.nickname}"
+ "#{Web.base_url()}/push/hub/#{user.nickname}"
end
def salmon_path(user) do
end
def remote_follow_path do
- "#{Web.base_url}/ostatus_subscribe?acct={uri}"
+ "#{Web.base_url()}/ostatus_subscribe?acct={uri}"
end
def handle_incoming(xml_string) do
with doc when doc != :error <- parse_document(xml_string) do
entries = :xmerl_xpath.string('//entry', doc)
- activities = Enum.map(entries, fn (entry) ->
- {:xmlObj, :string, object_type} = :xmerl_xpath.string('string(/entry/activity:object-type[1])', entry)
- {:xmlObj, :string, verb} = :xmerl_xpath.string('string(/entry/activity:verb[1])', entry)
- Logger.debug("Handling #{verb}")
-
- try do
- case verb do
- 'http://activitystrea.ms/schema/1.0/delete' ->
- with {:ok, activity} <- DeleteHandler.handle_delete(entry, doc), do: activity
- 'http://activitystrea.ms/schema/1.0/follow' ->
- with {:ok, activity} <- FollowHandler.handle(entry, doc), do: activity
- 'http://activitystrea.ms/schema/1.0/share' ->
- with {:ok, activity, retweeted_activity} <- handle_share(entry, doc), do: [activity, retweeted_activity]
- 'http://activitystrea.ms/schema/1.0/favorite' ->
- with {:ok, activity, favorited_activity} <- handle_favorite(entry, doc), do: [activity, favorited_activity]
- _ ->
- case object_type do
- 'http://activitystrea.ms/schema/1.0/note' ->
- with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
- 'http://activitystrea.ms/schema/1.0/comment' ->
- with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
- _ ->
- Logger.error("Couldn't parse incoming document")
- nil
- end
+ activities =
+ Enum.map(entries, fn entry ->
+ {:xmlObj, :string, object_type} =
+ :xmerl_xpath.string('string(/entry/activity:object-type[1])', entry)
+
+ {:xmlObj, :string, verb} = :xmerl_xpath.string('string(/entry/activity:verb[1])', entry)
+ Logger.debug("Handling #{verb}")
+
+ try do
+ case verb do
+ 'http://activitystrea.ms/schema/1.0/delete' ->
+ with {:ok, activity} <- DeleteHandler.handle_delete(entry, doc), do: activity
+
+ 'http://activitystrea.ms/schema/1.0/follow' ->
+ with {:ok, activity} <- FollowHandler.handle(entry, doc), do: activity
+
+ 'http://activitystrea.ms/schema/1.0/share' ->
+ with {:ok, activity, retweeted_activity} <- handle_share(entry, doc),
+ do: [activity, retweeted_activity]
+
+ 'http://activitystrea.ms/schema/1.0/favorite' ->
+ with {:ok, activity, favorited_activity} <- handle_favorite(entry, doc),
+ do: [activity, favorited_activity]
+
+ _ ->
+ case object_type do
+ 'http://activitystrea.ms/schema/1.0/note' ->
+ with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
+
+ 'http://activitystrea.ms/schema/1.0/comment' ->
+ with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
+
+ _ ->
+ Logger.error("Couldn't parse incoming document")
+ nil
+ end
+ end
+ rescue
+ e ->
+ Logger.error("Error occured while handling activity")
+ Logger.error(xml_string)
+ Logger.error(inspect(e))
+ nil
end
- rescue
- e ->
- Logger.error("Error occured while handling activity")
- Logger.error(xml_string)
- Logger.error(inspect(e))
- nil
- end
- end)
- |> Enum.filter(&(&1))
+ end)
+ |> Enum.filter(& &1)
{:ok, activities}
else
def get_or_try_fetching(entry) do
Logger.debug("Trying to get entry from db")
+
with id when not is_nil(id) <- string_from_xpath("//activity:object[1]/id", entry),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
{:ok, activity}
- else _ ->
+ else
+ _ ->
Logger.debug("Couldn't get, will try to fetch")
- with href when not is_nil(href) <- string_from_xpath("//activity:object[1]/link[@type=\"text/html\"]/@href", entry),
+
+ with href when not is_nil(href) <-
+ string_from_xpath("//activity:object[1]/link[@type=\"text/html\"]/@href", entry),
{:ok, [favorited_activity]} <- fetch_activity_from_url(href) do
{:ok, favorited_activity}
- else e -> Logger.debug("Couldn't find href: #{inspect(e)}")
+ else
+ e -> Logger.debug("Couldn't find href: #{inspect(e)}")
end
end
end
def get_attachments(entry) do
:xmerl_xpath.string('/entry/link[@rel="enclosure"]', entry)
- |> Enum.map(fn (enclosure) ->
+ |> Enum.map(fn enclosure ->
with href when not is_nil(href) <- string_from_xpath("/link/@href", enclosure),
type when not is_nil(type) <- string_from_xpath("/link/@type", enclosure) do
%{
"type" => "Attachment",
- "url" => [%{
- "type" => "Link",
- "mediaType" => type,
- "href" => href
- }]
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => type,
+ "href" => href
+ }
+ ]
}
end
end)
- |> Enum.filter(&(&1))
+ |> Enum.filter(& &1)
end
@doc """
def get_cw(entry) do
with cw when not is_nil(cw) <- string_from_xpath("/*/summary", entry) do
cw
- else _e -> nil
+ else
+ _e -> nil
end
end
def get_tags(entry) do
:xmerl_xpath.string('//category', entry)
- |> Enum.map(fn (category) -> string_from_xpath("/category/@term", category) end)
- |> Enum.filter(&(&1))
+ |> Enum.map(fn category -> string_from_xpath("/category/@term", category) end)
+ |> Enum.filter(& &1)
|> Enum.map(&String.downcase/1)
end
maybe_update_ostatus(doc, user)
end
end
+
def maybe_update_ostatus(doc, user) do
old_data = %{
avatar: user.avatar,
avatar <- make_avatar_object(doc),
bio <- string_from_xpath("//author[1]/summary", doc),
name <- string_from_xpath("//author[1]/poco:displayName", doc),
- info <- Map.put(user.info, "banner", make_avatar_object(doc, "header") || user.info["banner"]),
- new_data <- %{avatar: avatar || old_data.avatar, name: name || old_data.name, bio: bio || old_data.bio, info: info || old_data.info},
+ info <-
+ Map.put(user.info, "banner", make_avatar_object(doc, "header") || user.info["banner"]),
+ new_data <- %{
+ avatar: avatar || old_data.avatar,
+ name: name || old_data.name,
+ bio: bio || old_data.bio,
+ info: info || old_data.info
+ },
false <- new_data == old_data do
change = Ecto.Changeset.change(user, new_data)
Repo.update(change)
- else _ ->
- {:ok, user}
+ else
+ _ ->
+ {:ok, user}
end
end
def find_make_or_update_user(doc) do
uri = string_from_xpath("//author/uri[1]", doc)
+
with {:ok, user} <- find_or_make_user(uri) do
maybe_update(doc, user)
end
end
def find_or_make_user(uri) do
- query = from user in User,
- where: user.ap_id == ^uri
+ query = from(user in User, where: user.ap_id == ^uri)
user = Repo.one(query)
avatar: info["avatar"],
bio: info["bio"]
}
+
with false <- update,
%User{} = user <- User.get_by_ap_id(data.ap_id) do
{:ok, user}
- else _e -> User.insert_or_update_user(data)
+ else
+ _e -> User.insert_or_update_user(data)
end
end
end
if href do
%{
"type" => "Image",
- "url" =>
- [%{
- "type" => "Link",
- "mediaType" => type,
- "href" => href
- }]
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => type,
+ "href" => href
+ }
+ ]
}
else
nil
with {:ok, webfinger_data} <- WebFinger.finger(username),
{:ok, feed_data} <- Websub.gather_feed_data(webfinger_data["topic"]) do
{:ok, Map.merge(webfinger_data, feed_data) |> Map.put("fqn", username)}
- else e ->
- Logger.debug(fn -> "Couldn't gather info for #{username}" end)
- {:error, e}
+ else
+ e ->
+ Logger.debug(fn -> "Couldn't gather info for #{username}" end)
+ {:error, e}
end
end
Regex.match?(@mastodon_regex, body) ->
[[_, match]] = Regex.scan(@mastodon_regex, body)
{:ok, match}
+
Regex.match?(@gs_regex, body) ->
[[_, match]] = Regex.scan(@gs_regex, body)
{:ok, match}
+
Regex.match?(@gs_classic_regex, body) ->
[[_, match]] = Regex.scan(@gs_classic_regex, body)
{:ok, match}
+
true ->
Logger.debug(fn -> "Couldn't find Atom link in #{inspect(body)}" end)
{:error, "Couldn't find the Atom link"}
def fetch_activity_from_atom_url(url) do
with true <- String.starts_with?(url, "http"),
- {:ok, %{body: body, status_code: code}} when code in 200..299 <- @httpoison.get(url, [Accept: "application/atom+xml"], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
+ {:ok, %{body: body, status_code: code}} when code in 200..299 <-
+ @httpoison.get(
+ url,
+ [Accept: "application/atom+xml"],
+ follow_redirect: true,
+ timeout: 10000,
+ recv_timeout: 20000
+ ) do
Logger.debug("Got document from #{url}, handling...")
handle_incoming(body)
else
def fetch_activity_from_html_url(url) do
Logger.debug("Trying to fetch #{url}")
+
with true <- String.starts_with?(url, "http"),
- {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000),
+ {:ok, %{body: body}} <-
+ @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000),
{:ok, atom_url} <- get_atom_url(body) do
- fetch_activity_from_atom_url(atom_url)
+ fetch_activity_from_atom_url(atom_url)
else
e ->
Logger.debug("Couldn't get #{url}: #{inspect(e)}")
with {:ok, activities} when length(activities) > 0 <- fetch_activity_from_atom_url(url) do
{:ok, activities}
else
- _e -> with {:ok, activities} <- fetch_activity_from_html_url(url) do
- {:ok, activities}
- end
+ _e ->
+ with {:ok, activities} <- fetch_activity_from_html_url(url) do
+ {:ok, activities}
+ end
end
rescue
e ->
case get_format(conn) do
"html" -> Fallback.RedirectController.redirector(conn, nil)
"activity+json" -> ActivityPubController.user(conn, params)
- _ -> redirect conn, external: OStatus.feed_path(user)
+ _ -> redirect(conn, external: OStatus.feed_path(user))
end
end
def feed(conn, %{"nickname" => nickname} = params) do
user = User.get_cached_by_nickname(nickname)
- query_params = Map.take(params, ["max_id"])
- |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id})
+ query_params =
+ Map.take(params, ["max_id"])
+ |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id})
- activities = ActivityPub.fetch_public_activities(query_params)
- |> Enum.reverse
+ activities =
+ ActivityPub.fetch_public_activities(query_params)
+ |> Enum.reverse()
- response = user
- |> FeedRepresenter.to_simple_form(activities, [user])
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+ response =
+ user
+ |> FeedRepresenter.to_simple_form(activities, [user])
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
conn
|> put_resp_content_type("application/atom+xml")
else
with id <- o_status_url(conn, :object, uuid),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id),
- %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
+ %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do
"html" -> redirect(conn, to: "/notice/#{activity.id}")
_ -> represent_activity(conn, activity, user)
# TODO: Data leak
def notice(conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
- %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
+ with %Activity{} = activity <- Repo.get(Activity, id),
+ %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do
"html" ->
conn
|> put_resp_content_type("text/html")
|> send_file(200, "priv/static/index.html")
- _ -> represent_activity(conn, activity, user)
+
+ _ ->
+ represent_activity(conn, activity, user)
end
end
end
defp represent_activity(conn, activity, user) do
- response = activity
- |> ActivityRepresenter.to_simple_form(user, true)
- |> ActivityRepresenter.wrap_with_entry
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+ response =
+ activity
+ |> ActivityRepresenter.to_simple_form(user, true)
+ |> ActivityRepresenter.wrap_with_entry()
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
conn
|> put_resp_content_type("application/atom+xml")
defmodule Pleroma.Web.OStatus.UserRepresenter do
alias Pleroma.User
+
def to_simple_form(user) do
ap_id = to_charlist(user.ap_id)
nickname = to_charlist(user.nickname)
name = to_charlist(user.name)
bio = to_charlist(user.bio)
avatar_url = to_charlist(User.avatar_url(user))
- banner = if banner_url = User.banner_url(user) do
- [{:link, [rel: 'header', href: banner_url], []}]
- else
- []
- end
- ap_enabled = if user.local do
- [{:ap_enabled, ['true']}]
- else
- []
- end
+ banner =
+ if banner_url = User.banner_url(user) do
+ [{:link, [rel: 'header', href: banner_url], []}]
+ else
+ []
+ end
+
+ ap_enabled =
+ if user.local do
+ [{:ap_enabled, ['true']}]
+ else
+ []
+ end
[
{:id, [ap_id]},
end
pipeline :api do
- plug :accepts, ["json"]
- plug :fetch_session
- plug Pleroma.Plugs.OAuthPlug
- plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+ plug(:accepts, ["json"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true})
end
pipeline :authenticated_api do
- plug :accepts, ["json"]
- plug :fetch_session
- plug Pleroma.Plugs.OAuthPlug
- plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1}
+ plug(:accepts, ["json"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1})
end
pipeline :mastodon_html do
- plug :accepts, ["html"]
- plug :fetch_session
- plug Pleroma.Plugs.OAuthPlug
- plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+ plug(:accepts, ["html"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true})
end
pipeline :pleroma_html do
- plug :accepts, ["html"]
- plug :fetch_session
- plug Pleroma.Plugs.OAuthPlug
- plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true}
+ plug(:accepts, ["html"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Router.user_fetcher/1, optional: true})
end
pipeline :well_known do
- plug :accepts, ["xml", "xrd+xml", "json", "jrd+json"]
+ plug(:accepts, ["xml", "xrd+xml", "json", "jrd+json"])
end
pipeline :config do
- plug :accepts, ["json", "xml"]
+ plug(:accepts, ["json", "xml"])
end
pipeline :oauth do
- plug :accepts, ["html", "json"]
+ plug(:accepts, ["html", "json"])
end
pipeline :pleroma_api do
- plug :accepts, ["html", "json"]
+ plug(:accepts, ["html", "json"])
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
- pipe_through :pleroma_api
- get "/password_reset/:token", UtilController, :show_password_reset
- post "/password_reset", UtilController, :password_reset
- get "/emoji", UtilController, :emoji
+ pipe_through(:pleroma_api)
+ get("/password_reset/:token", UtilController, :show_password_reset)
+ post("/password_reset", UtilController, :password_reset)
+ get("/emoji", UtilController, :emoji)
end
scope "/", Pleroma.Web.TwitterAPI do
- pipe_through :pleroma_html
- get "/ostatus_subscribe", UtilController, :remote_follow
- post "/ostatus_subscribe", UtilController, :do_remote_follow
- post "/main/ostatus", UtilController, :remote_subscribe
+ pipe_through(:pleroma_html)
+ get("/ostatus_subscribe", UtilController, :remote_follow)
+ post("/ostatus_subscribe", UtilController, :do_remote_follow)
+ post("/main/ostatus", UtilController, :remote_subscribe)
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
- pipe_through :authenticated_api
- post "/follow_import", UtilController, :follow_import
+ pipe_through(:authenticated_api)
+ post("/follow_import", UtilController, :follow_import)
end
scope "/oauth", Pleroma.Web.OAuth do
- get "/authorize", OAuthController, :authorize
- post "/authorize", OAuthController, :create_authorization
- post "/token", OAuthController, :token_exchange
+ get("/authorize", OAuthController, :authorize)
+ post("/authorize", OAuthController, :create_authorization)
+ post("/token", OAuthController, :token_exchange)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
- pipe_through :authenticated_api
+ pipe_through(:authenticated_api)
- patch "/accounts/update_credentials", MastodonAPIController, :update_credentials
- get "/accounts/verify_credentials", MastodonAPIController, :verify_credentials
- get "/accounts/relationships", MastodonAPIController, :relationships
- get "/accounts/search", MastodonAPIController, :account_search
- post "/accounts/:id/follow", MastodonAPIController, :follow
- post "/accounts/:id/unfollow", MastodonAPIController, :unfollow
- post "/accounts/:id/block", MastodonAPIController, :block
- post "/accounts/:id/unblock", MastodonAPIController, :unblock
- post "/accounts/:id/mute", MastodonAPIController, :relationship_noop
- post "/accounts/:id/unmute", MastodonAPIController, :relationship_noop
+ patch("/accounts/update_credentials", MastodonAPIController, :update_credentials)
+ get("/accounts/verify_credentials", MastodonAPIController, :verify_credentials)
+ get("/accounts/relationships", MastodonAPIController, :relationships)
+ get("/accounts/search", MastodonAPIController, :account_search)
+ post("/accounts/:id/follow", MastodonAPIController, :follow)
+ post("/accounts/:id/unfollow", MastodonAPIController, :unfollow)
+ post("/accounts/:id/block", MastodonAPIController, :block)
+ post("/accounts/:id/unblock", MastodonAPIController, :unblock)
+ post("/accounts/:id/mute", MastodonAPIController, :relationship_noop)
+ post("/accounts/:id/unmute", MastodonAPIController, :relationship_noop)
- post "/follows", MastodonAPIController, :follow
+ post("/follows", MastodonAPIController, :follow)
- get "/blocks", MastodonAPIController, :blocks
+ get("/blocks", MastodonAPIController, :blocks)
- get "/domain_blocks", MastodonAPIController, :empty_array
- get "/follow_requests", MastodonAPIController, :empty_array
- get "/mutes", MastodonAPIController, :empty_array
+ get("/domain_blocks", MastodonAPIController, :empty_array)
+ get("/follow_requests", MastodonAPIController, :empty_array)
+ get("/mutes", MastodonAPIController, :empty_array)
- get "/timelines/home", MastodonAPIController, :home_timeline
+ get("/timelines/home", MastodonAPIController, :home_timeline)
- get "/favourites", MastodonAPIController, :favourites
+ get("/favourites", MastodonAPIController, :favourites)
- post "/statuses", MastodonAPIController, :post_status
- delete "/statuses/:id", MastodonAPIController, :delete_status
+ post("/statuses", MastodonAPIController, :post_status)
+ delete("/statuses/:id", MastodonAPIController, :delete_status)
- post "/statuses/:id/reblog", MastodonAPIController, :reblog_status
- post "/statuses/:id/favourite", MastodonAPIController, :fav_status
- post "/statuses/:id/unfavourite", MastodonAPIController, :unfav_status
+ post("/statuses/:id/reblog", MastodonAPIController, :reblog_status)
+ post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
+ post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
- post "/notifications/clear", MastodonAPIController, :clear_notifications
- post "/notifications/dismiss", MastodonAPIController, :dismiss_notification
- get "/notifications", MastodonAPIController, :notifications
- get "/notifications/:id", MastodonAPIController, :get_notification
+ post("/notifications/clear", MastodonAPIController, :clear_notifications)
+ post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
+ get("/notifications", MastodonAPIController, :notifications)
+ get("/notifications/:id", MastodonAPIController, :get_notification)
- post "/media", MastodonAPIController, :upload
+ post("/media", MastodonAPIController, :upload)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
- pipe_through :api
- get "/instance", MastodonAPIController, :masto_instance
- get "/instance/peers", MastodonAPIController, :peers
- post "/apps", MastodonAPIController, :create_app
- get "/custom_emojis", MastodonAPIController, :custom_emojis
-
- get "/timelines/public", MastodonAPIController, :public_timeline
- get "/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline
-
- get "/statuses/:id", MastodonAPIController, :get_status
- get "/statuses/:id/context", MastodonAPIController, :get_context
- get "/statuses/:id/card", MastodonAPIController, :empty_object
- get "/statuses/:id/favourited_by", MastodonAPIController, :favourited_by
- get "/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by
-
- get "/accounts/:id/statuses", MastodonAPIController, :user_statuses
- get "/accounts/:id/followers", MastodonAPIController, :followers
- get "/accounts/:id/following", MastodonAPIController, :following
- get "/accounts/:id", MastodonAPIController, :user
-
- get "/search", MastodonAPIController, :search
+ pipe_through(:api)
+ get("/instance", MastodonAPIController, :masto_instance)
+ get("/instance/peers", MastodonAPIController, :peers)
+ post("/apps", MastodonAPIController, :create_app)
+ get("/custom_emojis", MastodonAPIController, :custom_emojis)
+
+ get("/timelines/public", MastodonAPIController, :public_timeline)
+ get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
+
+ get("/statuses/:id", MastodonAPIController, :get_status)
+ get("/statuses/:id/context", MastodonAPIController, :get_context)
+ get("/statuses/:id/card", MastodonAPIController, :empty_object)
+ get("/statuses/:id/favourited_by", MastodonAPIController, :favourited_by)
+ get("/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by)
+
+ get("/accounts/:id/statuses", MastodonAPIController, :user_statuses)
+ get("/accounts/:id/followers", MastodonAPIController, :followers)
+ get("/accounts/:id/following", MastodonAPIController, :following)
+ get("/accounts/:id", MastodonAPIController, :user)
+
+ get("/search", MastodonAPIController, :search)
end
scope "/api", Pleroma.Web do
- pipe_through :config
+ pipe_through(:config)
- get "/help/test", TwitterAPI.UtilController, :help_test
- post "/help/test", TwitterAPI.UtilController, :help_test
- get "/statusnet/config", TwitterAPI.UtilController, :config
- get "/statusnet/version", TwitterAPI.UtilController, :version
+ get("/help/test", TwitterAPI.UtilController, :help_test)
+ post("/help/test", TwitterAPI.UtilController, :help_test)
+ get("/statusnet/config", TwitterAPI.UtilController, :config)
+ get("/statusnet/version", TwitterAPI.UtilController, :version)
end
@instance Application.get_env(:pleroma, :instance)
@registrations_open Keyword.get(@instance, :registrations_open)
scope "/api", Pleroma.Web do
- pipe_through :api
+ pipe_through(:api)
- get "/statuses/public_timeline", TwitterAPI.Controller, :public_timeline
- get "/statuses/public_and_external_timeline", TwitterAPI.Controller, :public_and_external_timeline
- get "/statuses/networkpublic_timeline", TwitterAPI.Controller, :public_and_external_timeline
- get "/statuses/user_timeline", TwitterAPI.Controller, :user_timeline
- get "/qvitter/statuses/user_timeline", TwitterAPI.Controller, :user_timeline
- get "/users/show", TwitterAPI.Controller, :show_user
+ get("/statuses/public_timeline", TwitterAPI.Controller, :public_timeline)
- get "/statuses/followers", TwitterAPI.Controller, :followers
- get "/statuses/friends", TwitterAPI.Controller, :friends
- get "/statuses/show/:id", TwitterAPI.Controller, :fetch_status
- get "/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation
+ get(
+ "/statuses/public_and_external_timeline",
+ TwitterAPI.Controller,
+ :public_and_external_timeline
+ )
+
+ get("/statuses/networkpublic_timeline", TwitterAPI.Controller, :public_and_external_timeline)
+ get("/statuses/user_timeline", TwitterAPI.Controller, :user_timeline)
+ get("/qvitter/statuses/user_timeline", TwitterAPI.Controller, :user_timeline)
+ get("/users/show", TwitterAPI.Controller, :show_user)
+
+ get("/statuses/followers", TwitterAPI.Controller, :followers)
+ get("/statuses/friends", TwitterAPI.Controller, :friends)
+ get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status)
+ get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation)
if @registrations_open do
- post "/account/register", TwitterAPI.Controller, :register
+ post("/account/register", TwitterAPI.Controller, :register)
end
- get "/search", TwitterAPI.Controller, :search
- get "/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline
+ get("/search", TwitterAPI.Controller, :search)
+ get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline)
end
scope "/api", Pleroma.Web do
- pipe_through :authenticated_api
+ pipe_through(:authenticated_api)
- get "/account/verify_credentials", TwitterAPI.Controller, :verify_credentials
- post "/account/verify_credentials", TwitterAPI.Controller, :verify_credentials
+ get("/account/verify_credentials", TwitterAPI.Controller, :verify_credentials)
+ post("/account/verify_credentials", TwitterAPI.Controller, :verify_credentials)
- post "/account/update_profile", TwitterAPI.Controller, :update_profile
- post "/account/update_profile_banner", TwitterAPI.Controller, :update_banner
- post "/qvitter/update_background_image", TwitterAPI.Controller, :update_background
+ post("/account/update_profile", TwitterAPI.Controller, :update_profile)
+ post("/account/update_profile_banner", TwitterAPI.Controller, :update_banner)
+ post("/qvitter/update_background_image", TwitterAPI.Controller, :update_background)
- post "/account/most_recent_notification", TwitterAPI.Controller, :update_most_recent_notification
+ post(
+ "/account/most_recent_notification",
+ TwitterAPI.Controller,
+ :update_most_recent_notification
+ )
- get "/statuses/home_timeline", TwitterAPI.Controller, :friends_timeline
- get "/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline
- get "/statuses/mentions", TwitterAPI.Controller, :mentions_timeline
- get "/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline
+ get("/statuses/home_timeline", TwitterAPI.Controller, :friends_timeline)
+ get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)
+ get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline)
+ get("/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline)
- post "/statuses/update", TwitterAPI.Controller, :status_update
- post "/statuses/retweet/:id", TwitterAPI.Controller, :retweet
- post "/statuses/destroy/:id", TwitterAPI.Controller, :delete_post
+ post("/statuses/update", TwitterAPI.Controller, :status_update)
+ post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
+ post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
- post "/friendships/create", TwitterAPI.Controller, :follow
- post "/friendships/destroy", TwitterAPI.Controller, :unfollow
- post "/blocks/create", TwitterAPI.Controller, :block
- post "/blocks/destroy", TwitterAPI.Controller, :unblock
+ post("/friendships/create", TwitterAPI.Controller, :follow)
+ post("/friendships/destroy", TwitterAPI.Controller, :unfollow)
+ post("/blocks/create", TwitterAPI.Controller, :block)
+ post("/blocks/destroy", TwitterAPI.Controller, :unblock)
- post "/statusnet/media/upload", TwitterAPI.Controller, :upload
- post "/media/upload", TwitterAPI.Controller, :upload_json
+ post("/statusnet/media/upload", TwitterAPI.Controller, :upload)
+ post("/media/upload", TwitterAPI.Controller, :upload_json)
- post "/favorites/create/:id", TwitterAPI.Controller, :favorite
- post "/favorites/create", TwitterAPI.Controller, :favorite
- post "/favorites/destroy/:id", TwitterAPI.Controller, :unfavorite
+ post("/favorites/create/:id", TwitterAPI.Controller, :favorite)
+ post("/favorites/create", TwitterAPI.Controller, :favorite)
+ post("/favorites/destroy/:id", TwitterAPI.Controller, :unfavorite)
- post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar
+ post("/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar)
- get "/friends/ids", TwitterAPI.Controller, :friends_ids
- get "/friendships/no_retweets/ids", TwitterAPI.Controller, :empty_array
+ get("/friends/ids", TwitterAPI.Controller, :friends_ids)
+ get("/friendships/no_retweets/ids", TwitterAPI.Controller, :empty_array)
- get "/mutes/users/ids", TwitterAPI.Controller, :empty_array
+ get("/mutes/users/ids", TwitterAPI.Controller, :empty_array)
- get "/externalprofile/show", TwitterAPI.Controller, :external_profile
+ get("/externalprofile/show", TwitterAPI.Controller, :external_profile)
end
pipeline :ostatus do
- plug :accepts, ["xml", "atom", "html", "activity+json"]
+ plug(:accepts, ["xml", "atom", "html", "activity+json"])
end
scope "/", Pleroma.Web do
- pipe_through :ostatus
+ pipe_through(:ostatus)
- get "/objects/:uuid", OStatus.OStatusController, :object
- get "/activities/:uuid", OStatus.OStatusController, :activity
- get "/notice/:id", OStatus.OStatusController, :notice
- get "/users/:nickname/feed", OStatus.OStatusController, :feed
- get "/users/:nickname", OStatus.OStatusController, :feed_redirect
+ get("/objects/:uuid", OStatus.OStatusController, :object)
+ get("/activities/:uuid", OStatus.OStatusController, :activity)
+ get("/notice/:id", OStatus.OStatusController, :notice)
+ get("/users/:nickname/feed", OStatus.OStatusController, :feed)
+ get("/users/:nickname", OStatus.OStatusController, :feed_redirect)
if @federating do
- post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming
- post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request
- get "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation
- post "/push/subscriptions/:id", Websub.WebsubController, :websub_incoming
+ post("/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming)
+ post("/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request)
+ get("/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation)
+ post("/push/subscriptions/:id", Websub.WebsubController, :websub_incoming)
end
-
end
pipeline :activitypub do
- plug :accepts, ["activity+json"]
- plug Pleroma.Web.Plugs.HTTPSignaturePlug
+ plug(:accepts, ["activity+json"])
+ plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
end
scope "/", Pleroma.Web.ActivityPub do
# XXX: not really ostatus
- pipe_through :ostatus
+ pipe_through(:ostatus)
- get "/users/:nickname/followers", ActivityPubController, :followers
- get "/users/:nickname/following", ActivityPubController, :following
- get "/users/:nickname/outbox", ActivityPubController, :outbox
+ get("/users/:nickname/followers", ActivityPubController, :followers)
+ get("/users/:nickname/following", ActivityPubController, :following)
+ get("/users/:nickname/outbox", ActivityPubController, :outbox)
end
if @federating do
scope "/", Pleroma.Web.ActivityPub do
- pipe_through :activitypub
- post "/users/:nickname/inbox", ActivityPubController, :inbox
- post "/inbox", ActivityPubController, :inbox
+ pipe_through(:activitypub)
+ post("/users/:nickname/inbox", ActivityPubController, :inbox)
+ post("/inbox", ActivityPubController, :inbox)
end
scope "/.well-known", Pleroma.Web do
- pipe_through :well_known
+ pipe_through(:well_known)
- get "/host-meta", WebFinger.WebFingerController, :host_meta
- get "/webfinger", WebFinger.WebFingerController, :webfinger
+ get("/host-meta", WebFinger.WebFingerController, :host_meta)
+ get("/webfinger", WebFinger.WebFingerController, :webfinger)
end
end
scope "/", Pleroma.Web.MastodonAPI do
- pipe_through :mastodon_html
+ pipe_through(:mastodon_html)
- get "/web/login", MastodonAPIController, :login
- post "/web/login", MastodonAPIController, :login_post
- get "/web/*path", MastodonAPIController, :index
- delete "/auth/sign_out", MastodonAPIController, :logout
+ get("/web/login", MastodonAPIController, :login)
+ post("/web/login", MastodonAPIController, :login_post)
+ get("/web/*path", MastodonAPIController, :index)
+ delete("/auth/sign_out", MastodonAPIController, :logout)
end
pipeline :remote_media do
- plug :accepts, ["html"]
+ plug(:accepts, ["html"])
end
+
scope "/proxy/", Pleroma.Web.MediaProxy do
- pipe_through :remote_media
- get "/:sig/:url", MediaProxyController, :remote
+ pipe_through(:remote_media)
+ get("/:sig/:url", MediaProxyController, :remote)
end
scope "/", Fallback do
- get "/*path", RedirectController, :redirector
+ get("/*path", RedirectController, :redirector)
end
end
defmodule Fallback.RedirectController do
use Pleroma.Web, :controller
+
def redirector(conn, _params) do
- if Mix.env != :test do
+ if Mix.env() != :test do
conn
|> put_resp_content_type("text/html")
|> send_file(200, "priv/static/index.html")
def decode_and_validate(magickey, salmon) do
[data, type, encoding, alg, sig] = decode(salmon)
- signed_text = [data, type, encoding, alg]
- |> Enum.map(&Base.url_encode64/1)
- |> Enum.join(".")
+ signed_text =
+ [data, type, encoding, alg]
+ |> Enum.map(&Base.url_encode64/1)
+ |> Enum.join(".")
key = decode_key(magickey)
end
def decode_key("RSA." <> magickey) do
- make_integer = fn(bin) ->
+ make_integer = fn bin ->
list = :erlang.binary_to_list(bin)
- Enum.reduce(list, 0, fn (el, acc) -> (acc <<< 8) ||| el end)
+ Enum.reduce(list, 0, fn el, acc -> acc <<< 8 ||| el end)
end
- [modulus, exponent] = magickey
- |> String.split(".")
- |> Enum.map(fn (n) -> Base.url_decode64!(n, padding: false) end)
- |> Enum.map(make_integer)
+ [modulus, exponent] =
+ magickey
+ |> String.split(".")
+ |> Enum.map(fn n -> Base.url_decode64!(n, padding: false) end)
+ |> Enum.map(make_integer)
{:RSAPublicKey, modulus, exponent}
end
def encode_key({:RSAPublicKey, modulus, exponent}) do
- modulus_enc = :binary.encode_unsigned(modulus) |> Base.url_encode64
- exponent_enc = :binary.encode_unsigned(exponent) |> Base.url_encode64
+ modulus_enc = :binary.encode_unsigned(modulus) |> Base.url_encode64()
+ exponent_enc = :binary.encode_unsigned(exponent) |> Base.url_encode64()
"RSA.#{modulus_enc}.#{exponent_enc}"
end
# We try at compile time to generate natively an RSA key otherwise we fallback on the old way.
try do
_ = :public_key.generate_key({:rsa, 2048, 65537})
+
def generate_rsa_pem do
key = :public_key.generate_key({:rsa, 2048, 65537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
- pem = :public_key.pem_encode([entry]) |> String.trim_trailing
+ pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
{:ok, pem}
end
rescue
_ ->
def generate_rsa_pem do
port = Port.open({:spawn, "openssl genrsa"}, [:binary])
- {:ok, pem} = receive do
- {^port, {:data, pem}} -> {:ok, pem}
- end
+
+ {:ok, pem} =
+ receive do
+ {^port, {:data, pem}} -> {:ok, pem}
+ end
+
Port.close(port)
+
if Regex.match?(~r/RSA PRIVATE KEY/, pem) do
{:ok, pem}
else
encoding = "base64url"
alg = "RSA-SHA256"
- signed_text = [doc, type, encoding, alg]
- |> Enum.map(&Base.url_encode64/1)
- |> Enum.join(".")
+ signed_text =
+ [doc, type, encoding, alg]
+ |> Enum.map(&Base.url_encode64/1)
+ |> Enum.join(".")
- signature = signed_text
- |> :public_key.sign(:sha256, private_key)
- |> to_string
- |> Base.url_encode64
+ signature =
+ signed_text
+ |> :public_key.sign(:sha256, private_key)
+ |> to_string
+ |> Base.url_encode64()
- doc_base64 = doc
- |> Base.url_encode64
+ doc_base64 =
+ doc
+ |> Base.url_encode64()
# Don't need proper xml building, these strings are safe to leave unescaped
salmon = """
def remote_users(%{data: %{"to" => to} = data}) do
to = to ++ (data["cc"] || [])
+
to
- |> Enum.map(fn(id) -> User.get_cached_by_ap_id(id) end)
- |> Enum.filter(fn(user) -> user && !user.local end)
+ |> Enum.map(fn id -> User.get_cached_by_ap_id(id) end)
+ |> Enum.filter(fn user -> user && !user.local end)
end
defp send_to_user(%{info: %{"salmon" => salmon}}, feed, poster) do
- with {:ok, %{status_code: code}} <- poster.(salmon, feed, [{"Content-Type", "application/magic-envelope+xml"}], timeout: 10000, recv_timeout: 20000, hackney: [pool: :default]) do
+ with {:ok, %{status_code: code}} <-
+ poster.(
+ salmon,
+ feed,
+ [{"Content-Type", "application/magic-envelope+xml"}],
+ timeout: 10000,
+ recv_timeout: 20000,
+ hackney: [pool: :default]
+ ) do
Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end)
else
e -> Logger.debug(fn -> "Pushing Salmon to #{salmon} failed, #{inspect(e)}" end)
end
end
- defp send_to_user(_,_,_), do: nil
+ defp send_to_user(_, _, _), do: nil
@supported_activities [
"Create",
"Delete"
]
def publish(user, activity, poster \\ &@httpoison.post/4)
- def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster) when type in @supported_activities do
- feed = ActivityRepresenter.to_simple_form(activity, user, true)
- |> ActivityRepresenter.wrap_with_entry
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+
+ def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster)
+ when type in @supported_activities do
+ feed =
+ ActivityRepresenter.to_simple_form(activity, user, true)
+ |> ActivityRepresenter.wrap_with_entry()
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
if feed do
{:ok, private, _} = keys_from_pem(keys)
{:ok, feed} = encode(private, feed)
remote_users(activity)
- |> Enum.each(fn(remote_user) ->
+ |> Enum.each(fn remote_user ->
Task.start(fn ->
Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end)
send_to_user(remote_user, feed, poster)
def start_link do
spawn(fn ->
- Process.sleep(1000 * 30) # 30 seconds
+ # 30 seconds
+ Process.sleep(1000 * 30)
GenServer.cast(__MODULE__, %{action: :ping})
end)
+
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
def handle_cast(%{action: :ping}, topics) do
Map.values(topics)
- |> List.flatten
- |> Enum.each(fn (socket) ->
+ |> List.flatten()
+ |> Enum.each(fn socket ->
Logger.debug("Sending keepalive ping")
- send socket.transport_pid, {:text, ""}
+ send(socket.transport_pid, {:text, ""})
end)
+
spawn(fn ->
- Process.sleep(1000 * 30) # 30 seconds
+ # 30 seconds
+ Process.sleep(1000 * 30)
GenServer.cast(__MODULE__, %{action: :ping})
end)
+
{:noreply, topics}
end
def handle_cast(%{action: :stream, topic: "user", item: %Notification{} = item}, topics) do
topic = "user:#{item.user_id}"
- Enum.each(topics[topic] || [], fn (socket) ->
- json = %{
- event: "notification",
- payload: Pleroma.Web.MastodonAPI.MastodonAPIController.render_notification(socket.assigns["user"], item) |> Jason.encode!
- } |> Jason.encode!
- send socket.transport_pid, {:text, json}
+ Enum.each(topics[topic] || [], fn socket ->
+ json =
+ %{
+ event: "notification",
+ payload:
+ Pleroma.Web.MastodonAPI.MastodonAPIController.render_notification(
+ socket.assigns["user"],
+ item
+ )
+ |> Jason.encode!()
+ }
+ |> Jason.encode!()
+
+ send(socket.transport_pid, {:text, json})
end)
+
{:noreply, topics}
end
def handle_cast(%{action: :stream, topic: "user", item: item}, topics) do
Logger.debug("Trying to push to users")
- recipient_topics = User.get_recipients_from_activity(item)
- |> Enum.map(fn (%{id: id}) -> "user:#{id}" end)
- Enum.each(recipient_topics, fn (topic) ->
+ recipient_topics =
+ User.get_recipients_from_activity(item)
+ |> Enum.map(fn %{id: id} -> "user:#{id}" end)
+
+ Enum.each(recipient_topics, fn topic ->
push_to_socket(topics, topic, item)
end)
+
{:noreply, topics}
end
end
def push_to_socket(topics, topic, item) do
- Enum.each(topics[topic] || [], fn (socket) ->
- json = %{
- event: "update",
- payload: Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: item, for: socket.assigns[:user]) |> Jason.encode!
- } |> Jason.encode!
-
- send socket.transport_pid, {:text, json}
+ Enum.each(topics[topic] || [], fn socket ->
+ json =
+ %{
+ event: "update",
+ payload:
+ Pleroma.Web.MastodonAPI.StatusView.render(
+ "status.json",
+ activity: item,
+ for: socket.assigns[:user]
+ )
+ |> Jason.encode!()
+ }
+ |> Jason.encode!()
+
+ send(socket.transport_pid, {:text, json})
end)
end
def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id) do
- render conn, "password_reset.html", %{
+ %User{} = user <- Repo.get(User, token.user_id) do
+ render(conn, "password_reset.html", %{
token: token,
user: user
- }
+ })
else
- _e -> render conn, "invalid_token.html"
+ _e -> render(conn, "invalid_token.html")
end
end
def password_reset(conn, %{"data" => data}) do
with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do
- render conn, "password_reset_success.html"
+ render(conn, "password_reset_success.html")
else
- _e -> render conn, "password_reset_failed.html"
+ _e -> render(conn, "password_reset_failed.html")
end
end
end
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
- with %User{} = user <- User.get_cached_by_nickname(nick),
- avatar = User.avatar_url(user) do
+ with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
conn
|> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
else
- _e -> render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Could not find user"})
+ _e ->
+ render(conn, "subscribe.html", %{
+ nickname: nick,
+ avatar: nil,
+ error: "Could not find user"
+ })
end
end
+
def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
%User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
|> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
else
_e ->
- render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Something went wrong."})
+ render(conn, "subscribe.html", %{
+ nickname: nick,
+ avatar: nil,
+ error: "Something went wrong."
+ })
end
end
|> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
else
conn
- |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
+ |> render("follow_login.html", %{
+ error: false,
+ acct: acct,
+ avatar: avatar,
+ name: name,
+ id: id
+ })
end
end
- def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
+ def do_remote_follow(conn, %{
+ "authorization" => %{"name" => username, "password" => password, "id" => id}
+ }) do
followee = Repo.get(User, id)
avatar = User.avatar_url(followee)
name = followee.nickname
+
with %User{} = user <- User.get_cached_by_nickname(username),
true <- Pbkdf2.checkpw(password, user.password_hash),
- %User{} = followed <- Repo.get(User, id),
+ %User{} = followed <- Repo.get(User, id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
else
_e ->
conn
- |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
+ |> render("follow_login.html", %{
+ error: "Wrong username or password",
+ id: id,
+ name: name,
+ avatar: avatar
+ })
end
end
+
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
with %User{} = followee <- Repo.get(User, id),
{:ok, follower} <- User.follow(user, followee),
|> render("followed.html", %{error: false})
else
e ->
- Logger.debug("Remote follow failed with error #{inspect e}")
- conn
- |> render("followed.html", %{error: inspect(e)})
+ Logger.debug("Remote follow failed with error #{inspect(e)}")
+
+ conn
+ |> render("followed.html", %{error: inspect(e)})
end
end
<config>
<site>
<name>#{Keyword.get(@instance, :name)}</name>
- <site>#{Web.base_url}</site>
+ <site>#{Web.base_url()}</site>
<textlimit>#{Keyword.get(@instance, :limit)}</textlimit>
<closed>#{!Keyword.get(@instance, :registrations_open)}</closed>
</site>
</config>
"""
+
conn
|> put_resp_content_type("application/xml")
|> send_resp(200, response)
+
_ ->
json(conn, %{
- site: %{
- name: Keyword.get(@instance, :name),
- server: Web.base_url,
- textlimit: to_string(Keyword.get(@instance, :limit)),
- closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1")
- }
- })
+ site: %{
+ name: Keyword.get(@instance, :name),
+ server: Web.base_url(),
+ textlimit: to_string(Keyword.get(@instance, :limit)),
+ closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1")
+ }
+ })
end
end
def version(conn, _params) do
version = Keyword.get(@instance, :version)
+
case get_format(conn) do
"xml" ->
response = "<version>#{version}</version>"
+
conn
|> put_resp_content_type("application/xml")
|> send_resp(200, response)
- _ -> json(conn, version)
+
+ _ ->
+ json(conn, version)
end
end
def emoji(conn, _params) do
- json conn, Enum.into(Formatter.get_custom_emoji(), %{})
+ json(conn, Enum.into(Formatter.get_custom_emoji(), %{}))
end
def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
follow_import(conn, %{"list" => File.read!(listfile.path)})
end
+
def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do
Task.start(fn ->
- String.split(list)
- |> Enum.map(fn nick ->
+ String.split(list)
+ |> Enum.map(fn nick ->
with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id),
- %User{} = followed <- User.get_or_fetch_by_nickname(nick),
- {:ok, follower} <- User.follow(follower, followed) do
+ %User{} = followed <- User.get_or_fetch_by_nickname(nick),
+ {:ok, follower} <- User.follow(follower, followed) do
ActivityPub.follow(follower, followed)
else
- _e -> Logger.debug "follow_import: following #{nick} failed"
+ _e -> Logger.debug("follow_import: following #{nick} failed")
end
end)
end)
- json conn, "job started"
+ json(conn, "job started")
end
end
alias Pleroma.Formatter
defp user_by_ap_id(user_list, ap_id) do
- Enum.find(user_list, fn (%{ap_id: user_id}) -> ap_id == user_id end)
+ Enum.find(user_list, fn %{ap_id: user_id} -> ap_id == user_id end)
end
- def to_map(%Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} = activity,
- %{users: users, announced_activity: announced_activity} = opts) do
+ def to_map(
+ %Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} =
+ activity,
+ %{users: users, announced_activity: announced_activity} = opts
+ ) do
user = user_by_ap_id(users, actor)
- created_at = created_at |> Utils.date_to_asctime
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} retweeted a status."
announced_user = user_by_ap_id(users, announced_activity.data["actor"])
retweeted_status = to_map(announced_activity, Map.merge(%{user: announced_user}, opts))
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
}
end
- def to_map(%Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
- %{user: user, liked_activity: liked_activity} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
+ %{user: user, liked_activity: liked_activity} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} favorited a status."
}
end
- def to_map(%Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity, %{user: user} = opts) do
- created_at = activity.data["published"] || (DateTime.to_iso8601(activity.inserted_at))
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity,
+ %{user: user} = opts
+ ) do
+ created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at)
+ created_at = created_at |> Utils.date_to_asctime()
followed = User.get_cached_by_ap_id(followed_id)
text = "#{user.nickname} started following #{followed.nickname}"
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
# TODO:
# Make this more proper. Just a placeholder to not break the frontend.
- def to_map(%Activity{data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity }} = activity, %{user: user} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{
+ data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity}
+ } = activity,
+ %{user: user} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} undid the action at #{undid_activity}"
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
}
end
- def to_map(%Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _ }} = activity, %{user: user} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _}} =
+ activity,
+ %{user: user} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"attentions" => [],
"statusnet_html" => "deleted notice {{tag",
- "text" => "deleted notice {{tag" ,
+ "text" => "deleted notice {{tag",
"is_local" => activity.local,
"is_post_verb" => false,
"created_at" => created_at,
}
end
- def to_map(%Activity{data: %{"object" => %{"content" => content} = object}} = activity, %{user: user} = opts) do
- created_at = object["published"] |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"object" => %{"content" => content} = object}} = activity,
+ %{user: user} = opts
+ ) do
+ created_at = object["published"] |> Utils.date_to_asctime()
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
mentions = opts[:mentioned] || []
- attentions = activity.recipients
- |> Enum.map(fn (ap_id) -> Enum.find(mentions, fn(user) -> ap_id == user.ap_id end) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn (user) -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
+ attentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> Enum.find(mentions, fn user -> ap_id == user.ap_id end) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
conversation_id = conversation_id(activity)
tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
summary = activity.data["object"]["summary"]
- content = if !!summary and summary != "" do
- "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
- else
- content
- end
- html = HtmlSanitizeEx.basic_html(content)
- |> Formatter.emojify(object["emoji"])
+ content =
+ if !!summary and summary != "" do
+ "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
+ else
+ content
+ end
+
+ html =
+ HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
%{
"id" => activity.id,
def conversation_id(activity) do
with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
- else _e -> nil
+ else
+ _e -> nil
end
end
defmodule Pleroma.Web.TwitterAPI.Representers.BaseRepresenter do
defmacro __using__(_opts) do
quote do
- def to_json(object) do to_json(object, %{}) end
+ def to_json(object) do
+ to_json(object, %{})
+ end
+
def to_json(object, options) do
object
|> to_map(options)
- |> Jason.encode!
+ |> Jason.encode!()
end
def enum_to_list(enum, options) do
- mapping = fn (el) -> to_map(el, options) end
+ mapping = fn el -> to_map(el, options) end
Enum.map(enum, mapping)
end
to_map(object, %{})
end
- def enum_to_json(enum) do enum_to_json(enum, %{}) end
+ def enum_to_json(enum) do
+ enum_to_json(enum, %{})
+ end
+
def enum_to_json(enum, options) do
enum
|> enum_to_list(options)
- |> Jason.encode!
+ |> Jason.encode!()
end
end
end
def to_map(%Object{data: %{"url" => [url | _]}} = object, _opts) do
data = object.data
+
%{
url: url["href"] |> Pleroma.Web.MediaProxy.url(),
mimetype: url["mediaType"],
end
def fetch_friend_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("blocking_user", user)
- |> Map.put("user", user)
- |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
+ opts =
+ opts
+ |> Map.put("blocking_user", user)
+ |> Map.put("user", user)
+ |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
ActivityPub.fetch_activities([user.ap_id | user.following], opts)
|> activities_to_statuses(%{for: user})
end
def fetch_public_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("local_only", true)
- |> Map.put("blocking_user", user)
- |> Map.put("type", ["Create", "Announce", "Follow"])
+ opts =
+ opts
+ |> Map.put("local_only", true)
+ |> Map.put("blocking_user", user)
+ |> Map.put("type", ["Create", "Announce", "Follow"])
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end
def fetch_public_and_external_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("blocking_user", user)
- |> Map.put("type", ["Create", "Announce", "Follow"])
+ opts =
+ opts
+ |> Map.put("blocking_user", user)
+ |> Map.put("type", ["Create", "Announce", "Follow"])
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end
def fetch_user_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("type", ["Create"])
+ opts =
+ opts
+ |> Map.put("type", ["Create"])
+
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end
def fetch_conversation(user, id) do
with context when is_binary(context) <- conversation_id_to_context(id),
- activities <- ActivityPub.fetch_activities_for_context(context, %{"blocking_user" => user, "user" => user}),
- statuses <- activities |> activities_to_statuses(%{for: user})
- do
+ activities <-
+ ActivityPub.fetch_activities_for_context(context, %{
+ "blocking_user" => user,
+ "user" => user
+ }),
+ statuses <- activities |> activities_to_statuses(%{for: user}) do
statuses
- else _e ->
- []
+ else
+ _e ->
+ []
end
end
def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
- {:ok, activity} <- ActivityPub.follow(follower, followed)
- do
+ {:ok, activity} <- ActivityPub.follow(follower, followed) do
{:ok, follower, followed, activity}
else
err -> err
end
def unfollow(%User{} = follower, params) do
- with { :ok, %User{} = unfollowed } <- get_user(params),
- { :ok, follower, follow_activity } <- User.unfollow(follower, unfollowed),
- { :ok, _activity } <- ActivityPub.insert(%{
- "type" => "Undo",
- "actor" => follower.ap_id,
- "object" => follow_activity.data["id"], # get latest Follow for these users
- "published" => make_date()
- })
- do
- { :ok, follower, unfollowed }
+ with {:ok, %User{} = unfollowed} <- get_user(params),
+ {:ok, follower, follow_activity} <- User.unfollow(follower, unfollowed),
+ {:ok, _activity} <-
+ ActivityPub.insert(%{
+ "type" => "Undo",
+ "actor" => follower.ap_id,
+ # get latest Follow for these users
+ "object" => follow_activity.data["id"],
+ "published" => make_date()
+ }) do
+ {:ok, follower, unfollowed}
else
err -> err
end
def block(%User{} = blocker, params) do
with {:ok, %User{} = blocked} <- get_user(params),
- {:ok, blocker} <- User.block(blocker, blocked)
- do
+ {:ok, blocker} <- User.block(blocker, blocked) do
{:ok, blocker, blocked}
else
err -> err
def unblock(%User{} = blocker, params) do
with {:ok, %User{} = blocked} <- get_user(params),
- {:ok, blocker} <- User.unblock(blocker, blocked)
- do
+ {:ok, blocker} <- User.unblock(blocker, blocked) do
{:ok, blocker, blocked}
else
err -> err
<atom:link rel="enclosure" href="#{href}" type="#{type}"></atom:link>
</rsp>
"""
+
"json" ->
%{
media_id: object.id,
media_id_string: "#{object.id}}",
media_url: href,
size: 0
- } |> Jason.encode!
+ }
+ |> Jason.encode!()
end
end
{:ok, user}
else
{:error, changeset} ->
- errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
- |> Jason.encode!
- {:error, %{error: errors}}
+ errors =
+ Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
+ |> Jason.encode!()
+
+ {:error, %{error: errors}}
end
end
case target = get_by_id_or_nickname(user_id) do
nil ->
{:error, "No user with such user_id"}
+
_ ->
{:ok, target}
end
+
%{"screen_name" => nickname} ->
case target = Repo.get_by(User, nickname: nickname) do
nil ->
{:error, "No user with such screen_name"}
+
_ ->
{:ok, target}
end
+
_ ->
if user do
{:ok, user}
end
defp parse_int(string, default)
+
defp parse_int(string, default) when is_binary(string) do
with {n, _} <- Integer.parse(string) do
n
_e -> default
end
end
+
defp parse_int(_, default), do: default
def search(user, %{"q" => query} = params) do
page = parse_int(params["page"], 1)
offset = (page - 1) * limit
- q = from a in Activity,
- where: fragment("?->>'type' = 'Create'", a.data),
- where: fragment("to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)", a.data, ^query),
- limit: ^limit,
- offset: ^offset,
- order_by: [desc: :inserted_at] # this one isn't indexed so psql won't take the wrong index.
+ q =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = 'Create'", a.data),
+ where:
+ fragment(
+ "to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)",
+ a.data,
+ ^query
+ ),
+ limit: ^limit,
+ offset: ^offset,
+ # this one isn't indexed so psql won't take the wrong index.
+ order_by: [desc: :inserted_at]
+ )
activities = Repo.all(q)
activities_to_statuses(activities, %{for: user})
end
defp activities_to_statuses(activities, opts) do
- Enum.map(activities, fn(activity) ->
+ Enum.map(activities, fn activity ->
activity_to_status(activity, opts)
end)
end
user = User.get_cached_by_ap_id(actor)
[liked_activity] = Activity.all_by_object_ap_id(activity.data["object"])
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, liked_activity: liked_activity}))
+ ActivityRepresenter.to_map(
+ activity,
+ Map.merge(opts, %{user: user, liked_activity: liked_activity})
+ )
end
# For announces, fetch the announced activity and the user.
[announced_activity] = Activity.all_by_object_ap_id(activity.data["object"])
announced_actor = User.get_cached_by_ap_id(announced_activity.data["actor"])
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{users: [user, announced_actor], announced_activity: announced_activity}))
+ ActivityRepresenter.to_map(
+ activity,
+ Map.merge(opts, %{users: [user, announced_actor], announced_activity: announced_activity})
+ )
end
defp activity_to_status(%Activity{data: %{"type" => "Delete"}} = activity, opts) do
actor = get_in(activity.data, ["actor"])
user = User.get_cached_by_ap_id(actor)
# mentioned_users = Repo.all(from user in User, where: user.ap_id in ^activity.data["to"])
- mentioned_users = Enum.map(activity.recipients || [], fn (ap_id) ->
- if ap_id do
- User.get_cached_by_ap_id(ap_id)
- else
- nil
- end
- end)
- |> Enum.filter(&(&1))
+ mentioned_users =
+ Enum.map(activity.recipients || [], fn ap_id ->
+ if ap_id do
+ User.get_cached_by_ap_id(ap_id)
+ else
+ nil
+ end
+ end)
+ |> Enum.filter(& &1)
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, mentioned: mentioned_users}))
+ ActivityRepresenter.to_map(
+ activity,
+ Map.merge(opts, %{user: user, mentioned: mentioned_users})
+ )
end
defp make_date do
- DateTime.utc_now() |> DateTime.to_iso8601
+ DateTime.utc_now() |> DateTime.to_iso8601()
end
def context_to_conversation_id(context) do
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
id
- else _e ->
+ else
+ _e ->
changeset = Object.context_mapping(context)
+
case Repo.insert(changeset) do
- {:ok, %{id: id}} -> id
+ {:ok, %{id: id}} ->
+ id
+
# This should be solved by an upsert, but it seems ecto
# has problems accessing the constraint inside the jsonb.
- {:error, _} -> Object.get_cached_by_ap_id(context).id
+ {:error, _} ->
+ Object.get_cached_by_ap_id(context).id
end
end
end
def conversation_id_to_context(id) do
with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
context
- else _e ->
- {:error, "No such conversation"}
+ else
+ _e ->
+ {:error, "No such conversation"}
end
end
with %User{} = user <- User.get_or_fetch(uri) do
spawn(fn ->
with url <- user.info["topic"],
- {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
+ {:ok, %{body: body}} <-
+ @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
OStatus.handle_incoming(body)
end
end)
+
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
- else _e ->
+ else
+ _e ->
{:error, "Couldn't find user"}
end
end
def status_update(%{assigns: %{user: user}} = conn, %{"status" => _} = status_data) do
with media_ids <- extract_media_ids(status_data),
- {:ok, activity} <- TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
+ {:ok, activity} <-
+ TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
conn
|> json(ActivityRepresenter.to_map(activity, %{user: user}))
else
defp extract_media_ids(status_data) do
with media_ids when not is_nil(media_ids) <- status_data["media_ids"],
split_ids <- String.split(media_ids, ","),
- clean_ids <- Enum.reject(split_ids, fn (id) -> String.length(id) == 0 end)
- do
- clean_ids
- else _e -> []
+ clean_ids <- Enum.reject(split_ids, fn id -> String.length(id) == 0 end) do
+ clean_ids
+ else
+ _e -> []
end
end
def show_user(conn, params) do
with {:ok, shown} <- TwitterAPI.get_user(params) do
if user = conn.assigns.user do
- render conn, UserView, "show.json", %{user: shown, for: user}
+ render(conn, UserView, "show.json", %{user: shown, for: user})
else
- render conn, UserView, "show.json", %{user: shown}
+ render(conn, UserView, "show.json", %{user: shown})
end
else
{:error, msg} ->
case TwitterAPI.get_user(user, params) do
{:ok, target_user} ->
params = Map.merge(params, %{"actor_id" => target_user.ap_id, "whole_db" => true})
- statuses = TwitterAPI.fetch_user_statuses(user, params)
+ statuses = TwitterAPI.fetch_user_statuses(user, params)
+
conn
- |> json_reply(200, statuses |> Jason.encode!)
+ |> json_reply(200, statuses |> Jason.encode!())
+
{:error, msg} ->
bad_request_reply(conn, msg)
end
case TwitterAPI.follow(user, params) do
{:ok, user, followed, _activity} ->
render(conn, UserView, "show.json", %{user: followed, for: user})
- {:error, msg} -> forbidden_json_reply(conn, msg)
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def block(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.block(user, params) do
{:ok, user, blocked} ->
- render conn, UserView, "show.json", %{user: blocked, for: user}
- {:error, msg} -> forbidden_json_reply(conn, msg)
+ render(conn, UserView, "show.json", %{user: blocked, for: user})
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def unblock(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.unblock(user, params) do
{:ok, user, blocked} ->
- render conn, UserView, "show.json", %{user: blocked, for: user}
- {:error, msg} -> forbidden_json_reply(conn, msg)
+ render(conn, UserView, "show.json", %{user: blocked, for: user})
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with {:ok, delete} <- CommonAPI.delete(id, user) do
json = ActivityRepresenter.to_json(delete, %{user: user, for: user})
+
conn
|> json_reply(200, json)
end
case TwitterAPI.unfollow(user, params) do
{:ok, user, unfollowed} ->
render(conn, UserView, "show.json", %{user: unfollowed, for: user})
- {:error, msg} -> forbidden_json_reply(conn, msg)
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{} = activity <- Repo.get(Activity, id),
true <- ActivityPub.visible_for_user?(activity, user) do
- render conn, ActivityView, "activity.json", %{activity: activity, for: user}
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
end
end
def upload(conn, %{"media" => media}) do
response = TwitterAPI.upload(media)
+
conn
|> put_resp_content_type("application/atom+xml")
|> send_resp(200, response)
def upload_json(conn, %{"media" => media}) do
response = TwitterAPI.upload(media, "json")
+
conn
|> json_reply(200, response)
end
def get_by_id_or_ap_id(id) do
activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
+
if activity.data["type"] == "Create" do
activity
else
render(conn, UserView, "show.json", %{user: user})
else
{:error, errors} ->
- conn
- |> json_reply(400, Jason.encode!(errors))
+ conn
+ |> json_reply(400, Jason.encode!(errors))
end
end
change <- User.info_changeset(user, %{info: new_info}),
{:ok, user} <- User.update_and_set_cache(change) do
CommonAPI.update(user)
- %{"url" => [ %{ "href" => href } | _ ]} = object.data
- response = %{ url: href } |> Jason.encode!
+ %{"url" => [%{"href" => href} | _]} = object.data
+ response = %{url: href} |> Jason.encode!()
+
conn
|> json_reply(200, response)
end
new_info <- Map.put(user.info, "background", object.data),
change <- User.info_changeset(user, %{info: new_info}),
{:ok, _user} <- User.update_and_set_cache(change) do
- %{"url" => [ %{ "href" => href } | _ ]} = object.data
- response = %{ url: href } |> Jason.encode!
+ %{"url" => [%{"href" => href} | _]} = object.data
+ response = %{url: href} |> Jason.encode!()
+
conn
|> json_reply(200, response)
end
def friends_ids(%{assigns: %{user: user}} = conn, _params) do
with {:ok, friends} <- User.get_friends(user) do
- ids = friends
- |> Enum.map(fn x -> x.id end)
- |> Jason.encode!
+ ids =
+ friends
+ |> Enum.map(fn x -> x.id end)
+ |> Jason.encode!()
json(conn, ids)
else
end
def update_profile(%{assigns: %{user: user}} = conn, params) do
- params = if bio = params["description"] do
- Map.put(params, "bio", bio)
- else
- params
- end
+ params =
+ if bio = params["description"] do
+ Map.put(params, "bio", bio)
+ else
+ params
+ end
with changeset <- User.update_changeset(user, params),
{:ok, user} <- User.update_and_set_cache(changeset) do
end
defp error_json(conn, error_message) do
- %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!
+ %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()
end
end
def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activity} = opts) do
user = User.get_by_ap_id(activity.data["actor"])
- created_at = activity.data["published"] |> Utils.date_to_asctime
+ created_at = activity.data["published"] |> Utils.date_to_asctime()
announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
text = "#{user.nickname} retweeted a status."
def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"])
liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
- created_at = activity.data["published"]
- |> Utils.date_to_asctime
+
+ created_at =
+ activity.data["published"]
+ |> Utils.date_to_asctime()
text = "#{user.nickname} favorited a status."
}
end
- def render("activity.json", %{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts) do
+ def render(
+ "activity.json",
+ %{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts
+ ) do
actor = get_in(activity.data, ["actor"])
user = User.get_cached_by_ap_id(actor)
- created_at = object["published"] |> Utils.date_to_asctime
+ created_at = object["published"] |> Utils.date_to_asctime()
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
- attentions = activity.recipients
- |> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn (user) -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
+ attentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
conversation_id = conversation_id(activity)
summary = activity.data["object"]["summary"]
content = object["content"]
- content = if !!summary and summary != "" do
- "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
- else
- content
- end
- html = HtmlSanitizeEx.basic_html(content)
- |> Formatter.emojify(object["emoji"])
+ content =
+ if !!summary and summary != "" do
+ "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
+ else
+ content
+ end
+
+ html =
+ HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
%{
"id" => activity.id,
defp conversation_id(activity) do
with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
- else _e -> nil
+ else
+ _e -> nil
end
end
end
def render("user.json", %{user: user = %User{}} = assigns) do
image = User.avatar_url(user) |> MediaProxy.url()
- {following, follows_you, statusnet_blocking} = if assigns[:for] do
- {
- User.following?(assigns[:for], user),
- User.following?(user, assigns[:for]),
- User.blocks?(assigns[:for], user)
- }
- else
- {false, false, false}
- end
+
+ {following, follows_you, statusnet_blocking} =
+ if assigns[:for] do
+ {
+ User.following?(assigns[:for], user),
+ User.following?(user, assigns[:for]),
+ User.blocks?(assigns[:for], user)
+ }
+ else
+ {false, false, false}
+ end
user_info = User.get_cached_user_info(user)
data = %{
- "created_at" => user.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"description" => HtmlSanitizeEx.strip_tags(user.bio),
"favourites_count" => 0,
"followers_count" => user_info[:follower_count],
end
end
- def render("short.json", %{user: %User{
- nickname: nickname, id: id, ap_id: ap_id, name: name
- }}) do
+ def render("short.json", %{
+ user: %User{
+ nickname: nickname,
+ id: id,
+ ap_id: ap_id,
+ name: name
+ }
+ }) do
%{
"fullname" => name,
"id" => id,
}
end
- defp image_url(%{"url" => [ %{ "href" => href } | _ ]}), do: href
+ defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
defp image_url(_), do: nil
end
# In case no render clause matches or no
# template is found, let's render it as 500
def template_not_found(_template, assigns) do
- render "500.json", assigns
+ render("500.json", assigns)
end
end
def view do
quote do
- use Phoenix.View, root: "lib/pleroma/web/templates",
- namespace: Pleroma.Web
+ use Phoenix.View,
+ root: "lib/pleroma/web/templates",
+ namespace: Pleroma.Web
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
end
def base_url do
- Pleroma.Web.Endpoint.url
+ Pleroma.Web.Endpoint.url()
end
end
require Logger
def host_meta do
- base_url = Web.base_url
+ base_url = Web.base_url()
+
{
- :XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
+ :XRD,
+ %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
{
- :Link, %{rel: "lrdd", type: "application/xrd+xml", template: "#{base_url}/.well-known/webfinger?resource={uri}"}
+ :Link,
+ %{
+ rel: "lrdd",
+ type: "application/xrd+xml",
+ template: "#{base_url}/.well-known/webfinger?resource={uri}"
+ }
}
}
- |> XmlBuilder.to_doc
+ |> XmlBuilder.to_doc()
end
def webfinger(resource, "JSON") do
- host = Pleroma.Web.Endpoint.host
+ host = Pleroma.Web.Endpoint.host()
regex = ~r/(acct:)?(?<username>\w+)@#{host}/
+
with %{"username" => username} <- Regex.named_captures(regex, resource) do
user = User.get_by_nickname(username)
{:ok, represent_user(user, "JSON")}
- else _e ->
- with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do
- {:ok, represent_user(user, "JSON")}
- else _e ->
- {:error, "Couldn't find user"}
- end
+ else
+ _e ->
+ with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do
+ {:ok, represent_user(user, "JSON")}
+ else
+ _e ->
+ {:error, "Couldn't find user"}
+ end
end
end
def webfinger(resource, "XML") do
- host = Pleroma.Web.Endpoint.host
+ host = Pleroma.Web.Endpoint.host()
regex = ~r/(acct:)?(?<username>\w+)@#{host}/
+
with %{"username" => username} <- Regex.named_captures(regex, resource) do
user = User.get_by_nickname(username)
{:ok, represent_user(user, "XML")}
- else _e ->
- with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do
- {:ok, represent_user(user, "XML")}
- else _e ->
- {:error, "Couldn't find user"}
- end
+ else
+ _e ->
+ with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do
+ {:ok, represent_user(user, "XML")}
+ else
+ _e ->
+ {:error, "Couldn't find user"}
+ end
end
end
{:ok, user} = ensure_keys_present(user)
{:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"])
magic_key = Salmon.encode_key(public)
+
%{
- "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host}",
+ "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}",
"aliases" => [user.ap_id],
"links" => [
- %{"rel" => "http://schemas.google.com/g/2010#updates-from", "type" => "application/atom+xml", "href" => OStatus.feed_path(user)},
- %{"rel" => "http://webfinger.net/rel/profile-page", "type" => "text/html", "href" => user.ap_id},
+ %{
+ "rel" => "http://schemas.google.com/g/2010#updates-from",
+ "type" => "application/atom+xml",
+ "href" => OStatus.feed_path(user)
+ },
+ %{
+ "rel" => "http://webfinger.net/rel/profile-page",
+ "type" => "text/html",
+ "href" => user.ap_id
+ },
%{"rel" => "salmon", "href" => OStatus.salmon_path(user)},
%{"rel" => "magic-public-key", "href" => "data:application/magic-public-key,#{magic_key}"},
%{"rel" => "self", "type" => "application/activity+json", "href" => user.ap_id},
- %{"rel" => "http://ostatus.org/schema/1.0/subscribe", "template" => OStatus.remote_follow_path()}
+ %{
+ "rel" => "http://ostatus.org/schema/1.0/subscribe",
+ "template" => OStatus.remote_follow_path()
+ }
]
}
end
{:ok, user} = ensure_keys_present(user)
{:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"])
magic_key = Salmon.encode_key(public)
+
{
- :XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
+ :XRD,
+ %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
[
- {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host}"},
+ {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"},
{:Alias, user.ap_id},
- {:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}},
- {:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
+ {:Link,
+ %{
+ rel: "http://schemas.google.com/g/2010#updates-from",
+ type: "application/atom+xml",
+ href: OStatus.feed_path(user)
+ }},
+ {:Link,
+ %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
{:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
- {:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
+ {:Link,
+ %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}},
{:Link, %{rel: "self", type: "application/activity+json", href: user.ap_id}},
- {:Link, %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
+ {:Link,
+ %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}}
]
}
- |> XmlBuilder.to_doc
+ |> XmlBuilder.to_doc()
end
# This seems a better fit in Salmon
def ensure_keys_present(user) do
info = user.info || %{}
+
if info["keys"] do
{:ok, user}
else
- {:ok, pem} = Salmon.generate_rsa_pem
+ {:ok, pem} = Salmon.generate_rsa_pem()
info = Map.put(info, "keys", pem)
+
Ecto.Changeset.change(user, info: info)
|> User.update_and_set_cache()
end
defp webfinger_from_xml(doc) do
magic_key = XML.string_from_xpath(~s{//Link[@rel="magic-public-key"]/@href}, doc)
"data:application/magic-public-key," <> magic_key = magic_key
- topic = XML.string_from_xpath(~s{//Link[@rel="http://schemas.google.com/g/2010#updates-from"]/@href}, doc)
+
+ topic =
+ XML.string_from_xpath(
+ ~s{//Link[@rel="http://schemas.google.com/g/2010#updates-from"]/@href},
+ doc
+ )
+
subject = XML.string_from_xpath("//Subject", doc)
salmon = XML.string_from_xpath(~s{//Link[@rel="salmon"]/@href}, doc)
- subscribe_address = XML.string_from_xpath(~s{//Link[@rel="http://ostatus.org/schema/1.0/subscribe"]/@template}, doc)
- ap_id = XML.string_from_xpath(~s{//Link[@rel="self" and @type="application/activity+json"]/@href}, doc)
+
+ subscribe_address =
+ XML.string_from_xpath(
+ ~s{//Link[@rel="http://ostatus.org/schema/1.0/subscribe"]/@template},
+ doc
+ )
+
+ ap_id =
+ XML.string_from_xpath(
+ ~s{//Link[@rel="self" and @type="application/activity+json"]/@href},
+ doc
+ )
+
data = %{
"magic_key" => magic_key,
"topic" => topic,
"subscribe_address" => subscribe_address,
"ap_id" => ap_id
}
+
{:ok, data}
end
defp webfinger_from_json(doc) do
- data = Enum.reduce(doc["links"], %{"subject" => doc["subject"]}, fn (link, data) ->
- case {link["type"], link["rel"]} do
- {"application/activity+json", "self"} ->
- Map.put(data, "ap_id", link["href"])
- {_, "magic-public-key"} ->
- "data:application/magic-public-key," <> magic_key = link["href"]
- Map.put(data, "magic_key", magic_key)
- {"application/atom+xml", "http://schemas.google.com/g/2010#updates-from"} ->
- Map.put(data, "topic", link["href"])
- {_, "salmon"} ->
- Map.put(data, "salmon", link["href"])
- {_, "http://ostatus.org/schema/1.0/subscribe"} ->
- Map.put(data, "subscribe_address", link["template"])
- _ ->
- Logger.debug("Unhandled type: #{inspect(link["type"])}")
- data
- end
- end)
+ data =
+ Enum.reduce(doc["links"], %{"subject" => doc["subject"]}, fn link, data ->
+ case {link["type"], link["rel"]} do
+ {"application/activity+json", "self"} ->
+ Map.put(data, "ap_id", link["href"])
+
+ {_, "magic-public-key"} ->
+ "data:application/magic-public-key," <> magic_key = link["href"]
+ Map.put(data, "magic_key", magic_key)
+
+ {"application/atom+xml", "http://schemas.google.com/g/2010#updates-from"} ->
+ Map.put(data, "topic", link["href"])
+
+ {_, "salmon"} ->
+ Map.put(data, "salmon", link["href"])
+
+ {_, "http://ostatus.org/schema/1.0/subscribe"} ->
+ Map.put(data, "subscribe_address", link["template"])
+
+ _ ->
+ Logger.debug("Unhandled type: #{inspect(link["type"])}")
+ data
+ end
+ end)
+
{:ok, data}
end
def get_template_from_xml(body) do
xpath = "//Link[@rel='lrdd' and @type='application/xrd+xml']/@template"
+
with doc when doc != :error <- XML.parse_document(body),
- template when template != nil <- XML.string_from_xpath(xpath, doc) do
+ template when template != nil <- XML.string_from_xpath(xpath, doc) do
{:ok, template}
end
end
def find_lrdd_template(domain) do
- with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- @httpoison.get("http://#{domain}/.well-known/host-meta", [], follow_redirect: true) do
+ with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <-
+ @httpoison.get("http://#{domain}/.well-known/host-meta", [], follow_redirect: true) do
get_template_from_xml(body)
else
_ ->
def finger(account) do
account = String.trim_leading(account, "@")
- domain = with [_name, domain] <- String.split(account, "@") do
- domain
- else _e ->
- URI.parse(account).host
- end
+
+ domain =
+ with [_name, domain] <- String.split(account, "@") do
+ domain
+ else
+ _e ->
+ URI.parse(account).host
+ end
case find_lrdd_template(domain) do
{:ok, template} ->
address = String.replace(template, "{uri}", URI.encode(account))
+
_ ->
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{account}"
end
- with response <- @httpoison.get(address, ["Accept": "application/xrd+xml,application/jrd+json"], follow_redirect: true),
+ with response <-
+ @httpoison.get(
+ address,
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ),
{:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response do
- doc = XML.parse_document(body)
- if doc != :error do
- webfinger_from_xml(doc)
- else
- {:ok, doc} = Jason.decode(body)
- webfinger_from_json(doc)
- end
+ doc = XML.parse_document(body)
+
+ if doc != :error do
+ webfinger_from_xml(doc)
+ else
+ {:ok, doc} = Jason.decode(body)
+ webfinger_from_json(doc)
+ end
else
e ->
Logger.debug(fn -> "Couldn't finger #{account}" end)
alias Pleroma.Web.WebFinger
def host_meta(conn, _params) do
- xml = WebFinger.host_meta
+ xml = WebFinger.host_meta()
conn
|> put_resp_content_type("application/xrd+xml")
else
_e -> send_resp(conn, 404, "Couldn't find user")
end
+
n when n in ["json", "jrd+json"] ->
with {:ok, response} <- WebFinger.webfinger(resource, "JSON") do
json(conn, response)
else
_e -> send_resp(conn, 404, "Couldn't find user")
end
+
_ ->
send_resp(conn, 404, "Unsupported format")
end
url = hd(String.split(subscription.callback, "?"))
query = URI.parse(subscription.callback).query || ""
params = Map.merge(params, URI.decode_query(query))
- with {:ok, response} <- getter.(url, [], [params: params]),
- ^challenge <- response.body
- do
+
+ with {:ok, response} <- getter.(url, [], params: params),
+ ^challenge <- response.body do
changeset = Changeset.change(subscription, %{state: "active"})
Repo.update(changeset)
- else e ->
- Logger.debug("Couldn't verify subscription")
- Logger.debug(inspect(e))
- {:error, subscription}
+ else
+ e ->
+ Logger.debug("Couldn't verify subscription")
+ Logger.debug(inspect(e))
+ {:error, subscription}
end
end
"Undo",
"Delete"
]
- def publish(topic, user, %{data: %{"type" => type}} = activity) when type in @supported_activities do
+ def publish(topic, user, %{data: %{"type" => type}} = activity)
+ when type in @supported_activities do
# TODO: Only send to still valid subscriptions.
- query = from sub in WebsubServerSubscription,
- where: sub.topic == ^topic and sub.state == "active",
- where: fragment("? > NOW()", sub.valid_until)
+ query =
+ from(
+ sub in WebsubServerSubscription,
+ where: sub.topic == ^topic and sub.state == "active",
+ where: fragment("? > NOW()", sub.valid_until)
+ )
+
subscriptions = Repo.all(query)
- Enum.each(subscriptions, fn(sub) ->
- response = user
- |> FeedRepresenter.to_simple_form([activity], [user])
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+
+ Enum.each(subscriptions, fn sub ->
+ response =
+ user
+ |> FeedRepresenter.to_simple_form([activity], [user])
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
data = %{
xml: response,
callback: sub.callback,
secret: sub.secret
}
+
Pleroma.Web.Federator.enqueue(:publish_single_websub, data)
end)
end
- def publish(_,_,_), do: ""
+
+ def publish(_, _, _), do: ""
def sign(secret, doc) do
- :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 |> String.downcase
+ :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16() |> String.downcase()
end
def incoming_subscription_request(user, %{"hub.mode" => "subscribe"} = params) do
with {:ok, topic} <- valid_topic(params, user),
{:ok, lease_time} <- lease_time(params),
secret <- params["hub.secret"],
- callback <- params["hub.callback"]
- do
+ callback <- params["hub.callback"] do
subscription = get_subscription(topic, callback)
+
data = %{
state: subscription.state || "requested",
topic: topic,
change = Changeset.change(subscription, data)
websub = Repo.insert_or_update!(change)
- change = Changeset.change(websub, %{valid_until:
- NaiveDateTime.add(websub.updated_at, lease_time)})
+ change =
+ Changeset.change(websub, %{valid_until: NaiveDateTime.add(websub.updated_at, lease_time)})
+
websub = Repo.update!(change)
Pleroma.Web.Federator.enqueue(:verify_websub, websub)
{:ok, websub}
- else {:error, reason} ->
- Logger.debug("Couldn't create subscription")
- Logger.debug(inspect(reason))
+ else
+ {:error, reason} ->
+ Logger.debug("Couldn't create subscription")
+ Logger.debug(inspect(reason))
- {:error, reason}
+ {:error, reason}
end
end
# Temp hack for mastodon.
defp lease_time(%{"hub.lease_seconds" => ""}) do
- {:ok, 60 * 60 * 24 * 3} # three days
+ # three days
+ {:ok, 60 * 60 * 24 * 3}
end
defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do
end
defp lease_time(_) do
- {:ok, 60 * 60 * 24 * 3} # three days
+ # three days
+ {:ok, 60 * 60 * 24 * 3}
end
defp valid_topic(%{"hub.topic" => topic}, user) do
def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do
topic = subscribed.info["topic"]
# FIXME: Race condition, use transactions
- {:ok, subscription} = with subscription when not is_nil(subscription) <- Repo.get_by(WebsubClientSubscription, topic: topic) do
- subscribers = [subscriber.ap_id | subscription.subscribers] |> Enum.uniq
- change = Ecto.Changeset.change(subscription, %{subscribers: subscribers})
- Repo.update(change)
- else _e ->
- subscription = %WebsubClientSubscription{
- topic: topic,
- hub: subscribed.info["hub"],
- subscribers: [subscriber.ap_id],
- state: "requested",
- secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64,
- user: subscribed
- }
- Repo.insert(subscription)
- end
+ {:ok, subscription} =
+ with subscription when not is_nil(subscription) <-
+ Repo.get_by(WebsubClientSubscription, topic: topic) do
+ subscribers = [subscriber.ap_id | subscription.subscribers] |> Enum.uniq()
+ change = Ecto.Changeset.change(subscription, %{subscribers: subscribers})
+ Repo.update(change)
+ else
+ _e ->
+ subscription = %WebsubClientSubscription{
+ topic: topic,
+ hub: subscribed.info["hub"],
+ subscribers: [subscriber.ap_id],
+ state: "requested",
+ secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64(),
+ user: subscribed
+ }
+
+ Repo.insert(subscription)
+ end
+
requester.(subscription)
end
doc <- XML.parse_document(body),
uri when not is_nil(uri) <- XML.string_from_xpath("/feed/author[1]/uri", doc),
hub when not is_nil(hub) <- XML.string_from_xpath(~S{/feed/link[@rel="hub"]/@href}, doc) do
-
name = XML.string_from_xpath("/feed/author[1]/name", doc)
preferredUsername = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc)
displayName = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc)
avatar = OStatus.make_avatar_object(doc)
bio = XML.string_from_xpath("/feed/author[1]/summary", doc)
- {:ok, %{
- "uri" => uri,
- "hub" => hub,
- "nickname" => preferredUsername || name,
- "name" => displayName || name,
- "host" => URI.parse(uri).host,
- "avatar" => avatar,
- "bio" => bio
- }}
- else e ->
- {:error, e}
+ {:ok,
+ %{
+ "uri" => uri,
+ "hub" => hub,
+ "nickname" => preferredUsername || name,
+ "name" => displayName || name,
+ "host" => URI.parse(uri).host,
+ "avatar" => avatar,
+ "bio" => bio
+ }}
+ else
+ e ->
+ {:error, e}
end
end
# This checks once a second if we are confirmed yet
websub_checker = fn ->
- helper = fn (helper) ->
+ helper = fn helper ->
:timer.sleep(1000)
websub = Repo.get_by(WebsubClientSubscription, id: websub.id, state: "accepted")
if websub, do: websub, else: helper.(helper)
end
+
helper.(helper)
end
task = Task.async(websub_checker)
- with {:ok, %{status_code: 202}} <- poster.(websub.hub, {:form, data}, ["Content-type": "application/x-www-form-urlencoded"]),
+ with {:ok, %{status_code: 202}} <-
+ poster.(websub.hub, {:form, data}, "Content-type": "application/x-www-form-urlencoded"),
{:ok, websub} <- Task.yield(task, timeout) do
{:ok, websub}
- else e ->
- Task.shutdown(task)
+ else
+ e ->
+ Task.shutdown(task)
- change = Ecto.Changeset.change(websub, %{state: "rejected"})
- {:ok, websub} = Repo.update(change)
+ change = Ecto.Changeset.change(websub, %{state: "rejected"})
+ {:ok, websub} = Repo.update(change)
- Logger.debug(fn -> "Couldn't confirm subscription: #{inspect(websub)}" end)
- Logger.debug(fn -> "error: #{inspect(e)}" end)
+ Logger.debug(fn -> "Couldn't confirm subscription: #{inspect(websub)}" end)
+ Logger.debug(fn -> "error: #{inspect(e)}" end)
- {:error, websub}
+ {:error, websub}
end
end
def refresh_subscriptions(delta \\ 60 * 60 * 24) do
Logger.debug("Refreshing subscriptions")
- cut_off = NaiveDateTime.add(NaiveDateTime.utc_now, delta)
+ cut_off = NaiveDateTime.add(NaiveDateTime.utc_now(), delta)
- query = from sub in WebsubClientSubscription,
- where: sub.valid_until < ^cut_off
+ query = from(sub in WebsubClientSubscription, where: sub.valid_until < ^cut_off)
subs = Repo.all(query)
- Enum.each(subs, fn (sub) ->
+ Enum.each(subs, fn sub ->
Pleroma.Web.Federator.enqueue(:request_subscription, sub)
end)
end
alias Pleroma.User
schema "websub_client_subscriptions" do
- field :topic, :string
- field :secret, :string
- field :valid_until, :naive_datetime
- field :state, :string
- field :subscribers, {:array, :string}, default: []
- field :hub, :string
- belongs_to :user, User
+ field(:topic, :string)
+ field(:secret, :string)
+ field(:valid_until, :naive_datetime)
+ field(:state, :string)
+ field(:subscribers, {:array, :string}, default: [])
+ field(:hub, :string)
+ belongs_to(:user, User)
timestamps()
end
def websub_subscription_request(conn, %{"nickname" => nickname} = params) do
user = User.get_cached_by_nickname(nickname)
- with {:ok, _websub} <- Websub.incoming_subscription_request(user, params)
- do
+ with {:ok, _websub} <- Websub.incoming_subscription_request(user, params) do
conn
|> send_resp(202, "Accepted")
- else {:error, reason} ->
- conn
- |> send_resp(500, reason)
+ else
+ {:error, reason} ->
+ conn
+ |> send_resp(500, reason)
end
end
# TODO: Extract this into the Websub module
- def websub_subscription_confirmation(conn, %{"id" => id, "hub.mode" => "subscribe", "hub.challenge" => challenge, "hub.topic" => topic} = params) do
+ def websub_subscription_confirmation(
+ conn,
+ %{
+ "id" => id,
+ "hub.mode" => "subscribe",
+ "hub.challenge" => challenge,
+ "hub.topic" => topic
+ } = params
+ ) do
Logger.debug("Got WebSub confirmation")
Logger.debug(inspect(params))
- lease_seconds = if params["hub.lease_seconds"] do
- String.to_integer(params["hub.lease_seconds"])
- else
- # Guess 3 days
- 60 * 60 * 24 * 3
- end
- with %WebsubClientSubscription{} = websub <- Repo.get_by(WebsubClientSubscription, id: id, topic: topic) do
- valid_until = NaiveDateTime.add(NaiveDateTime.utc_now, lease_seconds)
+ lease_seconds =
+ if params["hub.lease_seconds"] do
+ String.to_integer(params["hub.lease_seconds"])
+ else
+ # Guess 3 days
+ 60 * 60 * 24 * 3
+ end
+
+ with %WebsubClientSubscription{} = websub <-
+ Repo.get_by(WebsubClientSubscription, id: id, topic: topic) do
+ valid_until = NaiveDateTime.add(NaiveDateTime.utc_now(), lease_seconds)
change = Ecto.Changeset.change(websub, %{state: "accepted", valid_until: valid_until})
{:ok, _websub} = Repo.update(change)
+
conn
|> send_resp(200, challenge)
- else _e ->
- conn
- |> send_resp(500, "Error")
+ else
+ _e ->
+ conn
+ |> send_resp(500, "Error")
end
end
{:ok, body, _conn} = read_body(conn),
^signature <- Websub.sign(websub.secret, body) do
Federator.enqueue(:incoming_doc, body)
+
conn
|> send_resp(200, "OK")
- else _e ->
- Logger.debug("Can't handle incoming subscription post")
- conn
- |> send_resp(500, "Error")
+ else
+ _e ->
+ Logger.debug("Can't handle incoming subscription post")
+
+ conn
+ |> send_resp(500, "Error")
end
end
end
use Ecto.Schema
schema "websub_server_subscriptions" do
- field :topic, :string
- field :callback, :string
- field :secret, :string
- field :valid_until, :naive_datetime
- field :state, :string
+ field(:topic, :string)
+ field(:callback, :string)
+ field(:secret, :string)
+ field(:valid_until, :naive_datetime)
+ field(:state, :string)
timestamps()
end
require Logger
def string_from_xpath(_, :error), do: nil
+
def string_from_xpath(xpath, doc) do
{:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc)
- res = res
- |> to_string
- |> String.trim
+ res =
+ res
+ |> to_string
+ |> String.trim()
if res == "", do: nil, else: res
end
def parse_document(text) do
try do
- {doc, _rest} = text
- |> :binary.bin_to_list
- |> :xmerl_scan.string
+ {doc, _rest} =
+ text
+ |> :binary.bin_to_list()
+ |> :xmerl_scan.string()
doc
catch
defmodule Phoenix.Transports.WebSocket.Raw do
- import Plug.Conn, only: [
- fetch_query_params: 1,
- send_resp: 3
- ]
+ import Plug.Conn,
+ only: [
+ fetch_query_params: 1,
+ send_resp: 3
+ ]
+
alias Phoenix.Socket.Transport
def default_config do
def init(%Plug.Conn{method: "GET"} = conn, {endpoint, handler, transport}) do
{_, opts} = handler.__transport__(transport)
- conn = conn
- |> fetch_query_params
- |> Transport.transport_log(opts[:transport_log])
- |> Transport.force_ssl(handler, endpoint, opts)
- |> Transport.check_origin(handler, endpoint, opts)
+ conn =
+ conn
+ |> fetch_query_params
+ |> Transport.transport_log(opts[:transport_log])
+ |> Transport.force_ssl(handler, endpoint, opts)
+ |> Transport.check_origin(handler, endpoint, opts)
case conn do
%{halted: false} = conn ->
case Transport.connect(endpoint, handler, transport, __MODULE__, nil, conn.params) do
{:ok, socket} ->
{:ok, conn, {__MODULE__, {socket, opts}}}
+
:error ->
send_resp(conn, :forbidden, "")
{:error, conn}
end
+
_ ->
{:error, conn}
end
|> case do
{op, data} ->
{:reply, {op, data}, state}
+
{op, data, state} ->
{:reply, {op, data}, state}
+
%{} = state ->
{:ok, state}
+
_ ->
{:ok, state}
end
end
- def ws_info({_,_} = tuple, state) do
+ def ws_info({_, _} = tuple, state) do
{:reply, tuple, state}
end
for element <- content do
to_xml(element)
end
- |> Enum.join
+ |> Enum.join()
end
def to_xml(%NaiveDateTime{} = time) do
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 |> Enum.join(" ")
+ attributes_string =
+ for {attribute, value} <- attributes do
+ "#{attribute}=\"#{value}\""
+ end
+ |> Enum.join(" ")
- [tag, attributes_string] |> Enum.join(" ") |> String.trim
+ [tag, attributes_string] |> Enum.join(" ") |> String.trim()
end
end
use Mix.Project
def project do
- [app: :pleroma,
- version: "0.9.0",
- elixir: "~> 1.4",
- elixirc_paths: elixirc_paths(Mix.env),
- compilers: [:phoenix, :gettext] ++ Mix.compilers,
- start_permanent: Mix.env == :prod,
- aliases: aliases(),
- deps: deps()]
+ [
+ app: :pleroma,
+ version: "0.9.0",
+ elixir: "~> 1.4",
+ elixirc_paths: elixirc_paths(Mix.env()),
+ compilers: [:phoenix, :gettext] ++ Mix.compilers(),
+ start_permanent: Mix.env() == :prod,
+ aliases: aliases(),
+ deps: deps()
+ ]
end
# Configuration for the OTP application.
#
# Type `mix help compile.app` for more information.
def application do
- [mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin]]
+ [mod: {Pleroma.Application, []}, extra_applications: [:logger, :runtime_tools, :comeonin]]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
- defp elixirc_paths(_), do: ["lib"]
+ defp elixirc_paths(_), do: ["lib"]
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
defp deps do
- [{:phoenix, "~> 1.3.0"},
- {:phoenix_pubsub, "~> 1.0"},
- {:phoenix_ecto, "~> 3.2"},
- {:postgrex, ">= 0.0.0"},
- {:gettext, "~> 0.11"},
- {:cowboy, "~> 1.0", override: true},
- {:comeonin, "~> 3.0"},
- {:trailing_format_plug, "~> 0.0.5" },
- {:html_sanitize_ex, "~> 1.3.0-rc1"},
- {:phoenix_html, "~> 2.10"},
- {:calendar, "~> 0.16.1"},
- {:cachex, "~> 2.1"},
- {:httpoison, "~> 0.11.2"},
- {:jason, "~> 1.0"},
- {:ex_machina, "~> 2.0", only: :test},
- {:credo, "~> 0.7", only: [:dev, :test]}]
+ [
+ {:phoenix, "~> 1.3.0"},
+ {:phoenix_pubsub, "~> 1.0"},
+ {:phoenix_ecto, "~> 3.2"},
+ {:postgrex, ">= 0.0.0"},
+ {:gettext, "~> 0.11"},
+ {:cowboy, "~> 1.0", override: true},
+ {:comeonin, "~> 3.0"},
+ {:trailing_format_plug, "~> 0.0.5"},
+ {:html_sanitize_ex, "~> 1.3.0-rc1"},
+ {:phoenix_html, "~> 2.10"},
+ {:calendar, "~> 0.16.1"},
+ {:cachex, "~> 2.1"},
+ {:httpoison, "~> 0.11.2"},
+ {:jason, "~> 1.0"},
+ {:ex_machina, "~> 2.0", only: :test},
+ {:credo, "~> 0.7", only: [:dev, :test]}
+ ]
end
# Aliases are shortcuts or tasks specific to the current project.
#
# See the documentation for `Mix` for more info on aliases.
defp aliases do
- ["ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
- "ecto.reset": ["ecto.drop", "ecto.setup"],
- "test": ["ecto.create --quiet", "ecto.migrate", "test"]]
+ [
+ "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
+ "ecto.reset": ["ecto.drop", "ecto.setup"],
+ test: ["ecto.create --quiet", "ecto.migrate", "test"]
+ ]
end
end
test "returns the activity that created an object" do
activity = insert(:note_activity)
- found_activity = Pleroma.Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
+
+ found_activity =
+ Pleroma.Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])
assert activity == found_activity
end
describe ".add_hashtag_links" do
test "turns hashtags into links" do
text = "I love #cofe and #2hu"
- expected_text = "I love <a href='http://localhost:4001/tag/cofe' rel='tag'>#cofe</a> and <a href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a>"
+
+ expected_text =
+ "I love <a href='http://localhost:4001/tag/cofe' rel='tag'>#cofe</a> and <a href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a>"
tags = Formatter.parse_tags(text)
- assert expected_text == Formatter.add_hashtag_links({[], text}, tags) |> Formatter.finalize
+
+ assert expected_text ==
+ Formatter.add_hashtag_links({[], text}, tags) |> Formatter.finalize()
end
end
describe ".add_links" do
test "turning urls into links" do
text = "Hey, check out https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla."
- expected = "Hey, check out <a href='https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla'>https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla</a>."
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ expected =
+ "Hey, check out <a href='https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla'>https://www.youtube.com/watch?v=8Zg1-TufF%20zY?x=1&y=2#blabla</a>."
+
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
text = "https://mastodon.social/@lambadalambda"
- expected = "<a href='https://mastodon.social/@lambadalambda'>https://mastodon.social/@lambadalambda</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ expected =
+ "<a href='https://mastodon.social/@lambadalambda'>https://mastodon.social/@lambadalambda</a>"
+
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
text = "@lambadalambda"
expected = "@lambadalambda"
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
text = "http://www.cs.vu.nl/~ast/intel/"
expected = "<a href='http://www.cs.vu.nl/~ast/intel/'>http://www.cs.vu.nl/~ast/intel/</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
text = "https://forum.zdoom.org/viewtopic.php?f=44&t=57087"
- expected = "<a href='https://forum.zdoom.org/viewtopic.php?f=44&t=57087'>https://forum.zdoom.org/viewtopic.php?f=44&t=57087</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ expected =
+ "<a href='https://forum.zdoom.org/viewtopic.php?f=44&t=57087'>https://forum.zdoom.org/viewtopic.php?f=44&t=57087</a>"
+
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
text = "https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul"
- expected = "<a href='https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul'>https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul</a>"
- assert Formatter.add_links({[], text}) |> Formatter.finalize == expected
+ expected =
+ "<a href='https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul'>https://en.wikipedia.org/wiki/Sophia_(Gnosticism)#Mythos_of_the_soul</a>"
+
+ assert Formatter.add_links({[], text}) |> Formatter.finalize() == expected
end
end
{subs, text} = Formatter.add_user_links({[], text}, mentions)
assert length(subs) == 3
- Enum.each(subs, fn({uuid, _}) -> assert String.contains?(text, uuid) end)
+ Enum.each(subs, fn {uuid, _} -> assert String.contains?(text, uuid) end)
- expected_text = "<span><a href='#{gsimg.ap_id}'>@<span>gsimg</span></a></span> According to <span><a href='#{archaeme.ap_id}'>@<span>archaeme</span></a></span>, that is @daggsy. Also hello <span><a href='#{archaeme_remote.ap_id}'>@<span>archaeme</span></a></span>"
+ expected_text =
+ "<span><a href='#{gsimg.ap_id}'>@<span>gsimg</span></a></span> According to <span><a href='#{
+ archaeme.ap_id
+ }'>@<span>archaeme</span></a></span>, that is @daggsy. Also hello <span><a href='#{
+ archaeme_remote.ap_id
+ }'>@<span>archaeme</span></a></span>"
assert expected_text == Formatter.finalize({subs, text})
end
describe ".parse_tags" do
test "parses tags in the text" do
text = "Here's a #Test. Maybe these are #working or not. What about #漢字? And #は。"
+
expected = [
{"#Test", "test"},
{"#working", "working"},
expected_result = [
{"@gsimg", gsimg},
{"@archaeme", archaeme},
- {"@archaeme@archae.me", archaeme_remote},
+ {"@archaeme@archae.me", archaeme_remote}
]
assert Formatter.parse_mentions(text) == expected_result
test "it adds cool emoji" do
text = "I love :moominmamma:"
- expected_result = "I love <img height='32px' width='32px' alt='moominmamma' title='moominmamma' src='/finmoji/128px/moominmamma-128.png' />"
+ expected_result =
+ "I love <img height='32px' width='32px' alt='moominmamma' title='moominmamma' src='/finmoji/128px/moominmamma-128.png' />"
assert Formatter.emojify(text) == expected_result
end
other_user = insert(:user)
third_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{
+ "status" => "hey @#{other_user.nickname} and @#{third_user.nickname}"
+ })
{:ok, [notification, other_notification]} = Notification.create_notifications(activity)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.get(other_user, notification.id)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.get(user, notification.id)
end
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
{:ok, notification} = Notification.dismiss(other_user, notification.id)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
{:error, _notification} = Notification.dismiss(user, notification.id)
end
other_user = insert(:user)
third_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"})
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{
+ "status" => "hey @#{other_user.nickname} and @#{third_user.nickname} !"
+ })
+
{:ok, _notifs} = Notification.create_notifications(activity)
- {:ok, activity} = TwitterAPI.create_status(user, %{"status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"})
+
+ {:ok, activity} =
+ TwitterAPI.create_status(user, %{
+ "status" => "hey again @#{other_user.nickname} and @#{third_user.nickname} !"
+ })
+
{:ok, _notifs} = Notification.create_notifications(activity)
Notification.clear(other_user)
describe "without an authorization header" do
test "it halts the application" do
- conn = build_conn()
- |> Plug.Session.call(Plug.Session.init(@session_opts))
- |> fetch_session
- |> AuthenticationPlug.call(%{})
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session
+ |> AuthenticationPlug.call(%{})
assert conn.status == 403
assert conn.halted == true
end
test "it assigns a nil user if the 'optional' option is used" do
- conn = build_conn()
- |> Plug.Session.call(Plug.Session.init(@session_opts))
- |> fetch_session
- |> AuthenticationPlug.call(%{optional: true})
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session
+ |> AuthenticationPlug.call(%{optional: true})
- assert %{ user: nil } == conn.assigns
+ assert %{user: nil} == conn.assigns
end
end
build_conn()
|> Plug.Session.call(Plug.Session.init(@session_opts))
|> fetch_session
- |> AuthenticationPlug.call(%{optional: true, fetcher: &fetch_nil/1 })
+ |> AuthenticationPlug.call(%{optional: true, fetcher: &fetch_nil/1})
- assert %{ user: nil } == conn.assigns
+ assert %{user: nil} == conn.assigns
end
end
|> put_req_header("authorization", header)
|> AuthenticationPlug.call(opts)
- assert %{ user: nil } == conn.assigns
+ assert %{user: nil} == conn.assigns
end
end
header = basic_auth_enc("dude", "guy")
- conn = conn
+ conn =
+ conn
|> Plug.Session.call(Plug.Session.init(@session_opts))
|> fetch_session
|> put_req_header("authorization", header)
|> AuthenticationPlug.call(opts)
- assert %{ user: @user } == conn.assigns
+ assert %{user: @user} == conn.assigns
assert get_session(conn, :user_id) == @user.id
assert conn.halted == false
end
header = basic_auth_enc("dude", "guy")
- conn = conn
+ conn =
+ conn
|> Plug.Session.call(Plug.Session.init(@session_opts))
|> fetch_session
|> put_req_header("authorization", header)
header = basic_auth_enc("dude", "THIS IS WRONG")
- conn = conn
+ conn =
+ conn
|> Plug.Session.call(Plug.Session.init(@session_opts))
|> fetch_session
|> put_session(:user_id, @user.id)
|> put_req_header("authorization", header)
|> AuthenticationPlug.call(opts)
- assert %{ user: @user } == conn.assigns
+ assert %{user: @user} == conn.assigns
assert get_session(conn, :user_id) == @user.id
assert conn.halted == false
end
describe "with an assigned user" do
test "it does nothing, returning the incoming conn", %{conn: conn} do
- conn = conn
- |> assign(:user, @user)
+ conn =
+ conn
+ |> assign(:user, @user)
conn_result = AuthenticationPlug.call(conn, %{})
def build(data \\ %{}, opts \\ %{}) do
user = opts[:user] || Pleroma.Factory.insert(:user)
+
activity = %{
- "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"type" => "Create",
"object" => %{
"type" => "Note",
"content" => "test",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
}
+
Map.merge(activity, data)
end
end
def insert_list(times, data \\ %{}, opts \\ %{}) do
- Enum.map(1..times, fn (n) ->
+ Enum.map(1..times, fn n ->
{:ok, activity} = insert(data, opts)
activity
end)
bio: "A tester.",
ap_id: "some id"
}
+
Map.merge(user, data)
end
end
end
-
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
+
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})
end
+
:ok
end
-
end
end
end
-
setup tags do
Cachex.clear(:user_cache)
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
+
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})
end
+
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
-
end
password_hash: Comeonin.Pbkdf2.hashpwsalt("test"),
bio: sequence(:bio, &"Tester Number #{&1}")
}
- %{ user | ap_id: Pleroma.User.ap_id(user), follower_address: Pleroma.User.ap_followers(user), following: [Pleroma.User.ap_id(user)] }
+
+ %{
+ user
+ | ap_id: Pleroma.User.ap_id(user),
+ follower_address: Pleroma.User.ap_followers(user),
+ following: [Pleroma.User.ap_id(user)]
+ }
end
def note_factory do
text = sequence(:text, &"This is :moominmamma: note #{&1}")
user = insert(:user)
+
data = %{
"type" => "Note",
"content" => text,
- "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "published" => DateTime.utc_now() |> DateTime.to_iso8601,
+ "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"likes" => [],
"like_count" => 0,
"context" => "2hu",
def note_activity_factory do
note = insert(:note)
+
data = %{
- "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"],
"object" => note.data,
- "published" => DateTime.utc_now() |> DateTime.to_iso8601,
+ "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => note.data["context"]
}
user = insert(:user)
data = %{
- "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"actor" => user.ap_id,
"type" => "Like",
"object" => note_activity.data["object"]["id"],
- "published_at" => DateTime.utc_now() |> DateTime.to_iso8601
+ "published_at" => DateTime.utc_now() |> DateTime.to_iso8601()
}
%Pleroma.Activity{
followed = insert(:user)
data = %{
- "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"actor" => follower.ap_id,
"type" => "Follow",
"object" => followed.ap_id,
- "published_at" => DateTime.utc_now() |> DateTime.to_iso8601
+ "published_at" => DateTime.utc_now() |> DateTime.to_iso8601()
}
%Pleroma.Activity{
topic: "http://example.org",
callback: "http://example/org/callback",
secret: "here's a secret",
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, 100),
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 100),
state: "requested"
}
end
def get(url, body \\ [], headers \\ [])
- def get("http://framatube.org/.well-known/webfinger?resource=acct:framasoft@framatube.org", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/framasoft@framatube.org.json")
- }}
- end
- def get("http://gnusocial.de/.well-known/webfinger?resource=acct:winterdienst@gnusocial.de", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/winterdienst_webfinger.json")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "nonexistant@social.heldscal.la"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 500,
- body: File.read!("test/fixtures/httpoison_mock/nonexistant@social.heldscal.la.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/shp@social.heldscal.la.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "shp@social.heldscal.la"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/shp@social.heldscal.la.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://social.heldscal.la/user/23211"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_23211.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/23211", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_23211.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://social.heldscal.la/user/29191"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_29191.xml")
- }}
- end
-
- def get("https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/29191", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_29191.xml")
- }}
- end
-
- def get("https://mastodon.social/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://mastodon.social/users/lambadalambda"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.xml")
- }}
- end
-
- def get("https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/lambadalambda", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.xml")
- }}
- end
-
- def get("https://shitposter.club/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://shitposter.club/user/1"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_user_1.xml")
- }}
- end
-
- def get("https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/1", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_user_1.xml")
- }}
- end
-
- def get("https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/5381", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/spc_5381_xrd.xml")
- }}
- end
-
- def get("http://gs.example.org/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "http://gs.example.org:4040/index.php/user/1"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/http___gs.example.org_4040_index.php_user_1.xml")
- }}
- end
-
- def get("http://gs.example.org/.well-known/webfinger?resource=http://gs.example.org:4040/index.php/user/1", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/http___gs.example.org_4040_index.php_user_1.xml")
- }}
- end
-
- def get("https://social.stopwatchingus-heidelberg.de/.well-known/webfinger?resource=https://social.stopwatchingus-heidelberg.de/user/18330", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/atarifrosch_webfinger.xml")
- }}
- end
-
- def get("https://pleroma.soykaf.com/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://pleroma.soykaf.com/users/lain"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain.xml")
- }}
- end
-
- def get("https://pleroma.soykaf.com/.well-known/webfinger?resource=https://pleroma.soykaf.com/users/lain", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain.xml")
- }}
+ def get(
+ "http://framatube.org/.well-known/webfinger?resource=acct:framasoft@framatube.org",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/framasoft@framatube.org.json")
+ }}
+ end
+
+ def get(
+ "http://gnusocial.de/.well-known/webfinger?resource=acct:winterdienst@gnusocial.de",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/winterdienst_webfinger.json")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "nonexistant@social.heldscal.la"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 500,
+ body: File.read!("test/fixtures/httpoison_mock/nonexistant@social.heldscal.la.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/shp@social.heldscal.la.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "shp@social.heldscal.la"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/shp@social.heldscal.la.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://social.heldscal.la/user/23211"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_23211.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/23211",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_23211.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://social.heldscal.la/user/29191"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_29191.xml")
+ }}
+ end
+
+ def get(
+ "https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/29191",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_user_29191.xml")
+ }}
+ end
+
+ def get(
+ "https://mastodon.social/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://mastodon.social/users/lambadalambda"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.xml"
+ )
+ }}
+ end
+
+ def get(
+ "https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/lambadalambda",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.xml"
+ )
+ }}
+ end
+
+ def get(
+ "https://shitposter.club/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://shitposter.club/user/1"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_user_1.xml")
+ }}
+ end
+
+ def get(
+ "https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/1",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_user_1.xml")
+ }}
+ end
+
+ def get(
+ "https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/5381",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/spc_5381_xrd.xml")
+ }}
+ end
+
+ def get(
+ "http://gs.example.org/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "http://gs.example.org:4040/index.php/user/1"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/http___gs.example.org_4040_index.php_user_1.xml"
+ )
+ }}
+ end
+
+ def get(
+ "http://gs.example.org/.well-known/webfinger?resource=http://gs.example.org:4040/index.php/user/1",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/http___gs.example.org_4040_index.php_user_1.xml"
+ )
+ }}
+ end
+
+ def get(
+ "https://social.stopwatchingus-heidelberg.de/.well-known/webfinger?resource=https://social.stopwatchingus-heidelberg.de/user/18330",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/atarifrosch_webfinger.xml")
+ }}
+ end
+
+ def get(
+ "https://pleroma.soykaf.com/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://pleroma.soykaf.com/users/lain"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain.xml")
+ }}
+ end
+
+ def get(
+ "https://pleroma.soykaf.com/.well-known/webfinger?resource=https://pleroma.soykaf.com/users/lain",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain.xml")
+ }}
end
def get("https://social.heldscal.la/api/statuses/user_timeline/29191.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml"
+ )
+ }}
end
def get("https://shitposter.club/api/statuses/user_timeline/5381.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/spc_5381.atom")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/spc_5381.atom")
+ }}
end
def get("https://social.heldscal.la/api/statuses/user_timeline/23211.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml"
+ )
+ }}
end
def get("https://mastodon.social/users/lambadalambda.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.atom")
- }}
- end
-
- def get("https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/atarifrosch_feed.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___mastodon.social_users_lambadalambda.atom"
+ )
+ }}
+ end
+
+ def get(
+ "https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom",
+ _body,
+ _headers
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/atarifrosch_feed.xml")
+ }}
end
def get("https://pleroma.soykaf.com/users/lain/feed.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml"
+ )
+ }}
end
def get("https://social.sakamoto.gq/users/eal/feed.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/sakamoto_eal_feed.atom")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/sakamoto_eal_feed.atom")
+ }}
end
def get("http://gs.example.org/index.php/api/statuses/user_timeline/1.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml"
+ )
+ }}
end
def get("https://shitposter.club/notice/2827873", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_notice_2827873.html")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!("test/fixtures/httpoison_mock/https___shitposter.club_notice_2827873.html")
+ }}
end
def get("https://shitposter.club/api/statuses/show/2827873.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml"
+ )
+ }}
end
def get("https://shitposter.club/api/statuses/user_timeline/1.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml")
- }}
- end
-
- def post("https://social.heldscal.la/main/push/hub", {:form, data}, ["Content-type": "application/x-www-form-urlencoded"]) do
- {:ok, %Response{
- status_code: 202
- }}
- end
-
- def get("https://pawoo.net/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://pawoo.net/users/pekorino"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.xml")
- }}
- end
-
- def get("https://pawoo.net/.well-known/webfinger?resource=https://pawoo.net/users/pekorino", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!(
+ "test/fixtures/httpoison_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml"
+ )
+ }}
+ end
+
+ def post(
+ "https://social.heldscal.la/main/push/hub",
+ {:form, data},
+ "Content-type": "application/x-www-form-urlencoded"
+ ) do
+ {:ok,
+ %Response{
+ status_code: 202
+ }}
+ end
+
+ def get(
+ "https://pawoo.net/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://pawoo.net/users/pekorino"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.xml")
+ }}
+ end
+
+ def get(
+ "https://pawoo.net/.well-known/webfinger?resource=https://pawoo.net/users/pekorino",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.xml")
+ }}
end
def get("https://pawoo.net/users/pekorino.atom", _, _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.atom")
- }}
- end
-
- def get("https://mamot.fr/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://mamot.fr/users/Skruyb"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/skruyb@mamot.fr.atom")
- }}
- end
-
- def get("https://mamot.fr/.well-known/webfinger?resource=https://mamot.fr/users/Skruyb", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/skruyb@mamot.fr.atom")
- }}
- end
-
- def get("https://social.sakamoto.gq/.well-known/webfinger", [Accept: "application/xrd+xml,application/jrd+json"], [params: [resource: "https://social.sakamoto.gq/users/eal"], follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/eal_sakamoto.xml")
- }}
- end
-
- def get("https://social.sakamoto.gq/.well-known/webfinger?resource=https://social.sakamoto.gq/users/eal", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/eal_sakamoto.xml")
- }}
- end
-
- def get("https://pleroma.soykaf.com/.well-known/webfinger?resource=https://pleroma.soykaf.com/users/shp", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/shp@pleroma.soykaf.com.webfigner")
- }}
- end
-
- def get("https://squeet.me/xrd/?uri=lain@squeet.me", [Accept: "application/xrd+xml,application/jrd+json"], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/lain_squeet.me_webfinger.xml")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___pawoo.net_users_pekorino.atom")
+ }}
+ end
+
+ def get(
+ "https://mamot.fr/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://mamot.fr/users/Skruyb"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/skruyb@mamot.fr.atom")
+ }}
+ end
+
+ def get(
+ "https://mamot.fr/.well-known/webfinger?resource=https://mamot.fr/users/Skruyb",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/skruyb@mamot.fr.atom")
+ }}
+ end
+
+ def get(
+ "https://social.sakamoto.gq/.well-known/webfinger",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ params: [resource: "https://social.sakamoto.gq/users/eal"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/eal_sakamoto.xml")
+ }}
+ end
+
+ def get(
+ "https://social.sakamoto.gq/.well-known/webfinger?resource=https://social.sakamoto.gq/users/eal",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/eal_sakamoto.xml")
+ }}
+ end
+
+ def get(
+ "https://pleroma.soykaf.com/.well-known/webfinger?resource=https://pleroma.soykaf.com/users/shp",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/shp@pleroma.soykaf.com.webfigner")
+ }}
+ end
+
+ def get(
+ "https://squeet.me/xrd/?uri=lain@squeet.me",
+ [Accept: "application/xrd+xml,application/jrd+json"],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/lain_squeet.me_webfinger.xml")
+ }}
end
def get("https://mamot.fr/users/Skruyb.atom", _, _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/https___mamot.fr_users_Skruyb.atom")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/https___mamot.fr_users_Skruyb.atom")
+ }}
end
- def get("https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056", [Accept: "application/atom+xml"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/sakamoto.atom")
- }}
+ def get(
+ "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056",
+ [Accept: "application/atom+xml"],
+ _
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/sakamoto.atom")
+ }}
end
def get("https://pleroma.soykaf.com/users/shp/feed.atom", _, _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/shp@pleroma.soykaf.com.feed")
- }}
- end
-
- def get("http://social.heldscal.la/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/social.heldscal.la_host_meta")
- }}
- end
-
- def get("http://macgirvin.com/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/macgirvin.com_host_meta")
- }}
- end
-
- def get("http://mastodon.social/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/mastodon.social_host_meta")
- }}
- end
-
- def get("http://shitposter.club/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/shitposter.club_host_meta")
- }}
- end
-
- def get("http://pleroma.soykaf.com/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/pleroma.soykaf.com_host_meta")
- }}
- end
-
- def get("http://social.sakamoto.gq/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/social.sakamoto.gq_host_meta")
- }}
- end
-
- def get("http://gs.example.org/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/gs.example.org_host_meta")
- }}
- end
-
- def get("http://pawoo.net/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/pawoo.net_host_meta")
- }}
- end
-
- def get("http://mamot.fr/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/mamot.fr_host_meta")
- }}
- end
-
- def get("http://mastodon.xyz/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/mastodon.xyz_host_meta")
- }}
- end
-
- def get("http://social.wxcafe.net/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/social.wxcafe.net_host_meta")
- }}
- end
-
- def get("http://squeet.me/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/squeet.me_host_meta")
- }}
- end
-
- def get("http://social.stopwatchingus-heidelberg.de/.well-known/host-meta", [], [follow_redirect: true]) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/social.stopwatchingus-heidelberg.de_host_meta")
- }}
- end
-
- def get("http://mastodon.example.org/users/admin", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/admin@mastdon.example.org.json")
- }}
- end
-
- def get("https://masto.quad.moe/users/_HellPie", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/hellpie.json")
- }}
- end
-
- def get("https://niu.moe/users/rye", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/rye.json")
- }}
- end
-
- def get("https://mst3k.interlinked.me/users/luciferMysticus", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/lucifermysticus.json")
- }}
- end
-
- def get("https://mstdn.io/users/mayuutann", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/mayumayu.json")
- }}
- end
-
- def get("http://mastodon.example.org/@admin/99541947525187367", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/mastodon-note-object.json")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/shp@pleroma.soykaf.com.feed")
+ }}
end
- def get("https://mstdn.io/users/mayuutann/statuses/99568293732299394", ["Accept": "application/activity+json"], _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/mayumayupost.json")
- }}
+ def get("http://social.heldscal.la/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/social.heldscal.la_host_meta")
+ }}
+ end
+
+ def get("http://macgirvin.com/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/macgirvin.com_host_meta")
+ }}
+ end
+
+ def get("http://mastodon.social/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/mastodon.social_host_meta")
+ }}
+ end
+
+ def get("http://shitposter.club/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/shitposter.club_host_meta")
+ }}
+ end
+
+ def get("http://pleroma.soykaf.com/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/pleroma.soykaf.com_host_meta")
+ }}
+ end
+
+ def get("http://social.sakamoto.gq/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/social.sakamoto.gq_host_meta")
+ }}
+ end
+
+ def get("http://gs.example.org/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/gs.example.org_host_meta")
+ }}
+ end
+
+ def get("http://pawoo.net/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/pawoo.net_host_meta")
+ }}
+ end
+
+ def get("http://mamot.fr/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/mamot.fr_host_meta")
+ }}
+ end
+
+ def get("http://mastodon.xyz/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/mastodon.xyz_host_meta")
+ }}
+ end
+
+ def get("http://social.wxcafe.net/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/social.wxcafe.net_host_meta")
+ }}
+ end
+
+ def get("http://squeet.me/.well-known/host-meta", [], follow_redirect: true) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/squeet.me_host_meta")
+ }}
+ end
+
+ def get(
+ "http://social.stopwatchingus-heidelberg.de/.well-known/host-meta",
+ [],
+ follow_redirect: true
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body:
+ File.read!("test/fixtures/httpoison_mock/social.stopwatchingus-heidelberg.de_host_meta")
+ }}
+ end
+
+ def get("http://mastodon.example.org/users/admin", [Accept: "application/activity+json"], _) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/admin@mastdon.example.org.json")
+ }}
+ end
+
+ def get("https://masto.quad.moe/users/_HellPie", [Accept: "application/activity+json"], _) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/hellpie.json")
+ }}
+ end
+
+ def get("https://niu.moe/users/rye", [Accept: "application/activity+json"], _) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/rye.json")
+ }}
+ end
+
+ def get(
+ "https://mst3k.interlinked.me/users/luciferMysticus",
+ [Accept: "application/activity+json"],
+ _
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/lucifermysticus.json")
+ }}
+ end
+
+ def get("https://mstdn.io/users/mayuutann", [Accept: "application/activity+json"], _) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/mayumayu.json")
+ }}
+ end
+
+ def get(
+ "http://mastodon.example.org/@admin/99541947525187367",
+ [Accept: "application/activity+json"],
+ _
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/mastodon-note-object.json")
+ }}
+ end
+
+ def get(
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394",
+ [Accept: "application/activity+json"],
+ _
+ ) do
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/mayumayupost.json")
+ }}
end
def get("https://shitposter.club/notice/7369654", _, _) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/7369654.html")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/7369654.html")
+ }}
end
def get("https://shitposter.club/api/statuses/show/7369654.atom", _body, _headers) do
- {:ok, %Response{
- status_code: 200,
- body: File.read!("test/fixtures/httpoison_mock/7369654.atom")
- }}
+ {:ok,
+ %Response{
+ status_code: 200,
+ body: File.read!("test/fixtures/httpoison_mock/7369654.atom")
+ }}
end
def get(url, body, headers) do
- {:error, "Not implemented the mock response for get #{inspect(url)}, #{inspect(body)}, #{inspect(headers)}"}
+ {:error,
+ "Not implemented the mock response for get #{inspect(url)}, #{inspect(body)}, #{
+ inspect(headers)
+ }"}
end
def post(url, body, headers) do
defmodule Pleroma.Web.OStatusMock do
import Pleroma.Factory
+
def handle_incoming(_doc) do
insert(:note_activity)
end
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
{:ok, _} = Application.ensure_all_started(:ex_machina)
-
describe "Storing a file" do
test "copies the file to the configured folder" do
- file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an [image.jpg"}
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an [image.jpg"
+ }
+
data = Upload.store(file)
assert data["name"] == "an [image.jpg"
- assert List.first(data["url"])["href"] == "http://localhost:4001/media/#{data["uuid"]}/an%20%5Bimage.jpg"
+
+ assert List.first(data["url"])["href"] ==
+ "http://localhost:4001/media/#{data["uuid"]}/an%20%5Bimage.jpg"
end
test "fixes an incorrect content type" do
- file = %Plug.Upload{content_type: "application/octet-stream", path: Path.absname("test/fixtures/image.jpg"), filename: "an [image.jpg"}
+ file = %Plug.Upload{
+ content_type: "application/octet-stream",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an [image.jpg"
+ }
+
data = Upload.store(file)
assert hd(data["url"])["mediaType"] == "image/jpeg"
end
test "does not modify a valid content type" do
- file = %Plug.Upload{content_type: "image/png", path: Path.absname("test/fixtures/image.jpg"), filename: "an [image.jpg"}
+ file = %Plug.Upload{
+ content_type: "image/png",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an [image.jpg"
+ }
+
data = Upload.store(file)
assert hd(data["url"])["mediaType"] == "image/png"
end
import Ecto.Query
test "ap_id returns the activity pub id for the user" do
- user = UserBuilder.build
+ user = UserBuilder.build()
- expected_ap_id = "#{Pleroma.Web.base_url}/users/#{user.nickname}"
+ expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
assert expected_ap_id == User.ap_id(user)
end
test "ap_followers returns the followers collection for the user" do
- user = UserBuilder.build
+ user = UserBuilder.build()
expected_followers_collection = "#{User.ap_id(user)}/followers"
followed = insert(:user)
user = insert(:user, %{following: [User.ap_followers(followed)]})
- {:ok, user, _activity } = User.unfollow(user, followed)
+ {:ok, user, _activity} = User.unfollow(user, followed)
user = Repo.get(User, user.id)
assert user.following == [user.ap_id]
end
-
test "test if a user is following another user" do
followed = insert(:user)
user = insert(:user, %{following: [User.ap_followers(followed)]})
test "it requires an email, name, nickname and password, bio is optional" do
@full_user_data
- |> Map.keys
- |> Enum.each(fn (key) ->
+ |> Map.keys()
+ |> Enum.each(fn key ->
params = Map.delete(@full_user_data, key)
changeset = User.register_changeset(%User{}, params)
- assert (if key == :bio, do: changeset.valid?, else: not changeset.valid?)
+ assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
end)
end
assert is_binary(changeset.changes[:password_hash])
assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
- assert changeset.changes[:following] == [User.ap_followers(%User{nickname: @full_user_data.nickname})]
+
+ assert changeset.changes[:following] == [
+ User.ap_followers(%User{nickname: @full_user_data.nickname})
+ ]
+
assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
end
end
test "returns an ap_id for a user" do
user = insert(:user)
- assert User.ap_id(user) == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname)
+
+ assert User.ap_id(user) ==
+ Pleroma.Web.Router.Helpers.o_status_url(
+ Pleroma.Web.Endpoint,
+ :feed_redirect,
+ user.nickname
+ )
end
test "returns an ap_followers link for a user" do
user = insert(:user)
- assert User.ap_followers(user) == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) <> "/followers"
+
+ assert User.ap_followers(user) ==
+ Pleroma.Web.Router.Helpers.o_status_url(
+ Pleroma.Web.Endpoint,
+ :feed_redirect,
+ user.nickname
+ ) <> "/followers"
end
describe "remote user creation changeset" do
test "it sets the follower_adress" do
cs = User.remote_user_creation(@valid_remote)
# remote users get a fake local follower address
- assert cs.changes.follower_address == User.ap_followers(%User{ nickname: @valid_remote[:nickname] })
+ assert cs.changes.follower_address ==
+ User.ap_followers(%User{nickname: @valid_remote[:nickname]})
end
test "it enforces the fqn format for nicknames" do
test "it has required fields" do
[:name, :nickname, :ap_id]
- |> Enum.each(fn (field) ->
+ |> Enum.each(fn field ->
cs = User.remote_user_creation(Map.delete(@valid_remote, field))
refute cs.valid?
end)
test "it restricts some sizes" do
[bio: 5000, name: 100]
- |> Enum.each(fn ({field, size}) ->
+ |> Enum.each(fn {field, size} ->
string = String.pad_leading(".", size)
cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
assert cs.valid?
user_two = insert(:user, local: false)
addressed = insert(:user, local: true)
addressed_remote = insert(:user, local: false)
- {:ok, activity} = CommonAPI.post(actor, %{"status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"})
+
+ {:ok, activity} =
+ CommonAPI.post(actor, %{
+ "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
+ })
assert [addressed] == User.get_recipients_from_activity(activity)
test "insert or update a user from given data" do
user = insert(:user, %{nickname: "nick@name.de"})
- data = %{ ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname }
+ data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
assert {:ok, %User{}} = User.insert_or_update_user(data)
end
test "it returns a json representation of the user", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> put_req_header("accept", "application/activity+json")
- |> get("/users/#{user.nickname}")
+ conn =
+ conn
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/users/#{user.nickname}")
user = Repo.get(User, user.id)
describe "/object/:uuid" do
test "it returns a json representation of the object", %{conn: conn} do
note = insert(:note)
- uuid = String.split(note.data["id"], "/") |> List.last
+ uuid = String.split(note.data["id"], "/") |> List.last()
- conn = conn
- |> put_req_header("accept", "application/activity+json")
- |> get("/objects/#{uuid}")
+ conn =
+ conn
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/objects/#{uuid}")
assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
end
describe "/users/:nickname/inbox" do
test "it inserts an incoming activity into the database", %{conn: conn} do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
- conn = conn
- |> assign(:valid_signature, true)
- |> put_req_header("content-type", "application/activity+json")
- |> post("/inbox", data)
+ conn =
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/inbox", data)
assert "ok" == json_response(conn, 200)
:timer.sleep(500)
describe "insertion" do
test "returns the activity if one with the same id is already in" do
activity = insert(:note_activity)
- {:ok, new_activity}= ActivityPub.insert(activity.data)
+ {:ok, new_activity} = ActivityPub.insert(activity.data)
assert activity == new_activity
end
assert is_binary(activity.data["id"])
given_id = "bla"
+
data = %{
"ok" => true,
"id" => given_id
describe "create activities" do
test "removes doubled 'to' recipients" do
- {:ok, activity} = ActivityPub.create(%{to: ["user1", "user1", "user2"], actor: %User{ap_id: "1"}, context: "", object: %{}})
+ {:ok, activity} =
+ ActivityPub.create(%{
+ to: ["user1", "user1", "user2"],
+ actor: %User{ap_id: "1"},
+ context: "",
+ object: %{}
+ })
+
assert activity.data["to"] == ["user1", "user2"]
assert activity.actor == "1"
assert activity.recipients == ["user1", "user2"]
describe "public fetch activities" do
test "retrieves public activities" do
- _activities = ActivityPub.fetch_public_activities
+ _activities = ActivityPub.fetch_public_activities()
- %{public: public} = ActivityBuilder.public_and_non_public
+ %{public: public} = ActivityBuilder.public_and_non_public()
- activities = ActivityPub.fetch_public_activities
+ activities = ActivityPub.fetch_public_activities()
assert length(activities) == 1
assert Enum.at(activities, 0) == public
end
activities = ActivityBuilder.insert_list(30)
last_expected = List.last(activities)
- activities = ActivityPub.fetch_public_activities
+ activities = ActivityPub.fetch_public_activities()
last = List.last(activities)
assert length(activities) == 20
{:ok, announce_activity, object} = ActivityPub.announce(user, object)
assert object.data["announcement_count"] == 1
assert object.data["announcements"] == [user.ap_id]
- assert announce_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
+
+ assert announce_activity.data["to"] == [
+ User.ap_followers(user),
+ note_activity.data["actor"]
+ ]
+
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
describe "uploading files" do
test "copies the file to the configured folder" do
- file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "an_image.jpg"
describe "fetching an object" do
test "it fetches an object" do
- {:ok, object} = ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
+ {:ok, object} =
+ ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
+
assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
assert activity.data["id"]
- {:ok, object_again} = ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
+ {:ok, object_again} =
+ ActivityPub.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
assert [attachment] = object.data["attachment"]
assert is_list(attachment["url"])
assert activity = Activity.get_create_activity_by_object_ap_id(object.data["id"])
assert activity.data["id"]
- {:ok, object_again} = ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
+ {:ok, object_again} =
+ ActivityPub.fetch_object_from_id("https://shitposter.club/notice/2827873")
assert object == object_again
end
user = insert(:user)
{:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
- {:ok, update} = ActivityPub.update(%{actor: user_data["id"], to: [user.follower_address], cc: [], object: user_data})
+
+ {:ok, update} =
+ ActivityPub.update(%{
+ actor: user_data["id"],
+ to: [user.follower_address],
+ cc: [],
+ object: user_data
+ })
assert update.data["actor"] == user.ap_id
assert update.data["to"] == [user.follower_address]
test "it ignores an incoming notice if we already have it" do
activity = insert(:note_activity)
- data = File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!
- |> Map.put("object", activity.data["object"])
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("object", activity.data["object"])
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
end
test "it fetches replied-to activities if we don't have them" do
- data = File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
- object = data["object"]
- |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
- data = data
- |> Map.put("object", object)
+ data =
+ data
+ |> Map.put("object", object)
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
- assert activity = Activity.get_create_activity_by_object_ap_id("tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment")
- assert returned_activity.data["object"]["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
+ assert activity =
+ Activity.get_create_activity_by_object_ap_id(
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ )
+
+ assert returned_activity.data["object"]["inReplyToAtomUri"] ==
+ "https://shitposter.club/notice/2827873"
+
assert returned_activity.data["object"]["inReplyToStatusId"] == activity.id
end
test "it works for incoming notices" do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- assert data["id"] == "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
- assert data["context"] == "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
+ assert data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
+
+ assert data["context"] ==
+ "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
assert data["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
- ]
+ "http://mastodon.example.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ]
+
assert data["actor"] == "http://mastodon.example.org/users/admin"
object = data["object"]
assert object["id"] == "http://mastodon.example.org/users/admin/statuses/99512778738411822"
assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
assert object["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
- ]
+ "http://mastodon.example.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ]
+
assert object["actor"] == "http://mastodon.example.org/users/admin"
assert object["attributedTo"] == "http://mastodon.example.org/users/admin"
- assert object["context"] == "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
+ assert object["context"] ==
+ "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
assert object["sensitive"] == true
end
test "it works for incoming notices with hashtags" do
- data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!
+ data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert Enum.at(data["object"]["tag"], 2) == "moo"
test "it works for incoming follow requests" do
user = insert(:user)
- data = File.read!("test/fixtures/mastodon-follow-activity.json") |> Poison.decode!
- |> Map.put("object", user.ap_id)
+
+ data =
+ File.read!("test/fixtures/mastodon-follow-activity.json") |> Poison.decode!()
+ |> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
- data = File.read!("test/fixtures/mastodon-like.json") |> Poison.decode!
- |> Map.put("object", activity.data["object"]["id"])
+ data =
+ File.read!("test/fixtures/mastodon-like.json") |> Poison.decode!()
+ |> Map.put("object", activity.data["object"]["id"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
end
test "it works for incoming announces" do
- data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!
+ data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
- assert data["id"] == "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
- assert data["object"] == "http://mastodon.example.org/users/admin/statuses/99541947525187367"
+
+ assert data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
+
+ assert data["object"] ==
+ "http://mastodon.example.org/users/admin/statuses/99541947525187367"
assert Activity.get_create_activity_by_object_ap_id(data["object"])
end
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
- data = File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!
- |> Map.put("object", activity.data["object"]["id"])
+ data =
+ File.read!("test/fixtures/mastodon-announce.json")
+ |> Poison.decode!()
+ |> Map.put("object", activity.data["object"]["id"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["actor"] == "http://mastodon.example.org/users/admin"
assert data["type"] == "Announce"
- assert data["id"] == "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
+
+ assert data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
+
assert data["object"] == activity.data["object"]["id"]
assert Activity.get_create_activity_by_object_ap_id(data["object"]).id == activity.id
end
test "it works for incoming update activities" do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!
- object = update_data["object"]
- |> Map.put("actor", data["actor"])
- |> Map.put("id", data["actor"])
+ update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
+
+ object =
+ update_data["object"]
+ |> Map.put("actor", data["actor"])
+ |> Map.put("id", data["actor"])
- update_data = update_data
- |> Map.put("actor", data["actor"])
- |> Map.put("object", object)
+ update_data =
+ update_data
+ |> Map.put("actor", data["actor"])
+ |> Map.put("object", object)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
user = User.get_cached_by_ap_id(data["actor"])
assert user.name == "gargle"
- assert user.avatar["url"] == [%{"href" => "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"}]
- assert user.info["banner"]["url"] == [%{"href" => "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"}]
+
+ assert user.avatar["url"] == [
+ %{
+ "href" =>
+ "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
+ }
+ ]
+
+ assert user.info["banner"]["url"] == [
+ %{
+ "href" =>
+ "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
+ }
+ ]
+
assert user.bio == "<p>Some bio</p>"
end
test "it works for incoming deletes" do
activity = insert(:note_activity)
- data = File.read!("test/fixtures/mastodon-delete.json")
- |> Poison.decode!
- object = data["object"]
- |> Map.put("id", activity.data["object"]["id"])
+ data =
+ File.read!("test/fixtures/mastodon-delete.json")
+ |> Poison.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("id", activity.data["object"]["id"])
- data = data
- |> Map.put("object", object)
- |> Map.put("actor", activity.data["actor"])
+ data =
+ data
+ |> Map.put("object", object)
+ |> Map.put("actor", activity.data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
object = modified["object"]
}
expected_tag = %{
- "href" => Pleroma.Web.Endpoint.url <> "/tags/2hu",
+ "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
"type" => "Hashtag",
"name" => "#2hu"
}
user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
+
{:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29"
describe "user upgrade" do
test "it upgrades a user to activitypub" do
- user = insert(:user, %{nickname: "rye@niu.moe", local: false, ap_id: "https://niu.moe/users/rye", follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})})
+ user =
+ insert(:user, %{
+ nickname: "rye@niu.moe",
+ local: false,
+ ap_id: "https://niu.moe/users/rye",
+ follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
+ })
+
user_two = insert(:user, %{following: [user.follower_address]})
{:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
activity = Repo.get(Activity, activity.id)
assert user.follower_address in activity.recipients
- assert %{"url" => [%{"href" => "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"}]} = user.avatar
- assert %{"url" => [%{"href" => "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"}]} = user.info["banner"]
+
+ assert %{
+ "url" => [
+ %{
+ "href" =>
+ "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
+ }
+ ]
+ } = user.avatar
+
+ assert %{
+ "url" => [
+ %{
+ "href" =>
+ "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
+ }
+ ]
+ } = user.info["banner"]
+
refute "..." in activity.recipients
unrelated_activity = Repo.get(Activity, unrelated_activity.id)
use Pleroma.DataCase
test "it adds attachment links to a given text and attachment set" do
- name = "Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png"
+ name =
+ "Sakura%20Mana%20%E2%80%93%20Turned%20on%20by%20a%20Senior%20OL%20with%20a%20Temptating%20Tight%20Skirt-s%20Full%20Hipline%20and%20Panty%20Shot-%20Beautiful%20Thick%20Thighs-%20and%20Erotic%20Ass-%20-2015-%20--%20Oppaitime%208-28-2017%206-50-33%20PM.png"
attachment = %{
"url" => [%{"href" => name}]
res = Utils.add_attachments("", [attachment])
- assert res == "<br><a href=\"#{name}\" class='attachment'>Sakura Mana – Turned on by a Se…</a>"
+ assert res ==
+ "<br><a href=\"#{name}\" class='attachment'>Sakura Mana – Turned on by a Se…</a>"
end
end
alias Pleroma.User
test "Represent a user account" do
- user = insert(:user, %{info: %{"note_count" => 5, "follower_count" => 3}, nickname: "shp@shitposter.club", inserted_at: ~N[2017-08-15 15:47:06.597036]})
+ user =
+ insert(:user, %{
+ info: %{"note_count" => 5, "follower_count" => 3},
+ nickname: "shp@shitposter.club",
+ inserted_at: ~N[2017-08-15 15:47:06.597036]
+ })
expected = %{
id: to_string(user.id),
{:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/timelines/home")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/timelines/home")
assert length(json_response(conn, 200)) == 0
{:ok, user} = User.follow(user, following)
- conn = build_conn()
- |> assign(:user, user)
- |> get("/api/v1/timelines/home")
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> get("/api/v1/timelines/home")
assert [%{"content" => "test"}] = json_response(conn, 200)
end
test "the public timeline", %{conn: conn} do
following = insert(:user)
- capture_log fn ->
+ capture_log(fn ->
{:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
- {:ok, [_activity]} = OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
- conn = conn
- |> get("/api/v1/timelines/public", %{"local" => "False"})
+ {:ok, [_activity]} =
+ OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
+
+ conn =
+ conn
+ |> get("/api/v1/timelines/public", %{"local" => "False"})
assert length(json_response(conn, 200)) == 2
- conn = build_conn()
- |> get("/api/v1/timelines/public", %{"local" => "True"})
+ conn =
+ build_conn()
+ |> get("/api/v1/timelines/public", %{"local" => "True"})
assert [%{"content" => "test"}] = json_response(conn, 200)
- conn = build_conn()
- |> get("/api/v1/timelines/public", %{"local" => "1"})
+ conn =
+ build_conn()
+ |> get("/api/v1/timelines/public", %{"local" => "1"})
assert [%{"content" => "test"}] = json_response(conn, 200)
- end
+ end)
end
test "posting a status", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "cofe", "spoiler_text" => "2hu", "sensitive" => "false"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
+
+ assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
+ json_response(conn, 200)
- assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} = json_response(conn, 200)
assert Repo.get(Activity, id)
end
test "posting a sensitive status", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
assert Repo.get(Activity, id)
{:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
test "verify_credentials", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/verify_credentials")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/verify_credentials")
assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(user.id)
test "get a status", %{conn: conn} do
activity = insert(:note_activity)
- conn = conn
- |> get("/api/v1/statuses/#{activity.id}")
+ conn =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}")
assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(activity.id)
activity = insert(:note_activity)
author = User.get_by_ap_id(activity.data["actor"])
- conn = conn
- |> assign(:user, author)
- |> delete("/api/v1/statuses/#{activity.id}")
+ conn =
+ conn
+ |> assign(:user, author)
+ |> delete("/api/v1/statuses/#{activity.id}")
assert %{} = json_response(conn, 200)
activity = insert(:note_activity)
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> delete("/api/v1/statuses/#{activity.id}")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> delete("/api/v1/statuses/#{activity.id}")
assert %{"error" => _} = json_response(conn, 403)
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+
{:ok, [_notification]} = Notification.create_notifications(activity)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/notifications")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/notifications")
+
+ expected_response =
+ "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
- expected_response = "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
assert response == expected_response
end
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/notifications/#{notification.id}")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/notifications/#{notification.id}")
+
+ expected_response =
+ "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
- expected_response = "hi <span><a href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
assert %{"status" => %{"content" => response}} = json_response(conn, 200)
assert response == expected_response
end
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+
{:ok, [notification]} = Notification.create_notifications(activity)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
assert %{} = json_response(conn, 200)
end
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+ {:ok, activity} =
+ TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
+
{:ok, [_notification]} = Notification.create_notifications(activity)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/notifications/clear")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/notifications/clear")
assert %{} = json_response(conn, 200)
- conn = build_conn()
- |> assign(:user, user)
- |> get("/api/v1/notifications")
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> get("/api/v1/notifications")
assert all = json_response(conn, 200)
assert all == []
activity = insert(:note_activity)
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/reblog")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+ assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
+ json_response(conn, 200)
- assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} = json_response(conn, 200)
assert to_string(activity.id) == id
end
end
activity = insert(:note_activity)
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/favourite")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/favourite")
+
+ assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
+ json_response(conn, 200)
- assert %{"id" => id, "favourites_count" => 1, "favourited" => true} = json_response(conn, 200)
assert to_string(activity.id) == id
end
end
{:ok, _, _} = CommonAPI.favorite(activity.id, user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/unfavourite")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unfavourite")
+
+ assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
+ json_response(conn, 200)
- assert %{"id" => id, "favourites_count" => 0, "favourited" => false} = json_response(conn, 200)
assert to_string(activity.id) == id
end
end
user = User.get_by_ap_id(note_two.data["actor"])
- conn = conn
- |> get("/api/v1/accounts/#{user.id}/statuses")
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/statuses")
assert [%{"id" => id}] = json_response(conn, 200)
note = insert(:note_activity)
user = User.get_by_ap_id(note.data["actor"])
- file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
- media = TwitterAPI.upload(file, "json")
- |> Poison.decode!
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
- {:ok, image_post} = TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
+ media =
+ TwitterAPI.upload(file, "json")
+ |> Poison.decode!()
- conn = conn
- |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
+ {:ok, image_post} =
+ TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
+
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(image_post.id)
- conn = build_conn()
- |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
+ conn =
+ build_conn()
+ |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(image_post.id)
other_user = insert(:user)
{:ok, user} = User.follow(user, other_user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
assert [relationship] = json_response(conn, 200)
test "account fetching", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> get("/api/v1/accounts/#{user.id}")
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}")
assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(user.id)
- conn = build_conn()
- |> get("/api/v1/accounts/-1")
+ conn =
+ build_conn()
+ |> get("/api/v1/accounts/-1")
assert %{"error" => "Can't find user"} = json_response(conn, 404)
end
test "media upload", %{conn: conn} do
- file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/media", %{"file" => file})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/media", %{"file" => file})
assert media = json_response(conn, 200)
test "hashtag timeline", %{conn: conn} do
following = insert(:user)
- capture_log fn ->
+ capture_log(fn ->
{:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
- {:ok, [_activity]} = OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
- conn = conn
- |> get("/api/v1/timelines/tag/2hu")
+
+ {:ok, [_activity]} =
+ OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
+
+ conn =
+ conn
+ |> get("/api/v1/timelines/tag/2hu")
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(activity.id)
- end
+ end)
end
test "getting followers", %{conn: conn} do
other_user = insert(:user)
{:ok, user} = User.follow(user, other_user)
- conn = conn
- |> get("/api/v1/accounts/#{other_user.id}/followers")
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{other_user.id}/followers")
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(user.id)
other_user = insert(:user)
{:ok, user} = User.follow(user, other_user)
- conn = conn
- |> get("/api/v1/accounts/#{user.id}/following")
+ conn =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/following")
assert [%{"id" => id}] = json_response(conn, 200)
assert id == to_string(other_user.id)
user = insert(:user)
other_user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/follow")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/follow")
assert %{"id" => _id, "following" => true} = json_response(conn, 200)
user = Repo.get(User, user.id)
- conn = build_conn()
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/unfollow")
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/unfollow")
assert %{"id" => _id, "following" => false} = json_response(conn, 200)
user = Repo.get(User, user.id)
- conn = build_conn()
- |> assign(:user, user)
- |> post("/api/v1/follows", %{"uri" => other_user.nickname})
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/follows", %{"uri" => other_user.nickname})
assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(other_user.id)
user = insert(:user)
other_user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/block")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/block")
assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
user = Repo.get(User, user.id)
- conn = build_conn()
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/unblock")
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/unblock")
assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
end
{:ok, user} = User.block(user, other_user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/blocks")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/blocks")
other_user_id = to_string(other_user.id)
assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
other_user = insert(:user)
["mute", "unmute"]
- |> Enum.each(fn(endpoint) ->
- conn = build_conn()
- |> assign(:user, user)
- |> post("/api/v1/accounts/#{other_user.id}/#{endpoint}")
+ |> Enum.each(fn endpoint ->
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> post("/api/v1/accounts/#{other_user.id}/#{endpoint}")
assert %{"id" => id} = json_response(conn, 200)
assert id == to_string(other_user.id)
user = insert(:user)
["blocks", "domain_blocks", "mutes", "follow_requests"]
- |> Enum.each(fn(endpoint) ->
- conn = build_conn()
- |> assign(:user, user)
- |> get("/api/v1/#{endpoint}")
+ |> Enum.each(fn endpoint ->
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> get("/api/v1/#{endpoint}")
assert [] = json_response(conn, 200)
end)
_user_two = insert(:user, %{nickname: "shp@shitposter.club"})
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/search", %{"q" => "2hu"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/search", %{"q" => "2hu"})
assert [account] = json_response(conn, 200)
assert account["id"] == to_string(user_three.id)
{:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
{:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
- conn = conn
- |> get("/api/v1/search", %{"q" => "2hu"})
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "2hu"})
assert results = json_response(conn, 200)
end
test "search fetches remote statuses", %{conn: conn} do
- capture_log fn ->
- conn = conn
- |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
+ capture_log(fn ->
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
+
assert results = json_response(conn, 200)
[status] = results["statuses"]
assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
- end
+ end)
end
test "search fetches remote accounts", %{conn: conn} do
- conn = conn
- |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
+ conn =
+ conn
+ |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
assert results = json_response(conn, 200)
[account] = results["accounts"]
{:ok, _, _} = CommonAPI.favorite(activity.id, user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/v1/favourites")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/favourites")
assert [status] = json_response(conn, 200)
assert status["id"] == to_string(activity.id)
test "updates the user's bio", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"note" => "I drink #cofe"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"note" => "I drink #cofe"})
assert user = json_response(conn, 200)
assert user["note"] == "I drink #cofe"
test "updates the user's name", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
assert user = json_response(conn, 200)
assert user["display_name"] == "markorepairs"
test "updates the user's avatar", %{conn: conn} do
user = insert(:user)
- new_avatar = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
+ new_avatar = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
- conn = conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
assert user = json_response(conn, 200)
assert user["avatar"] != "https://placehold.it/48x48"
test "updates the user's banner", %{conn: conn} do
user = insert(:user)
- new_header = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
+ new_header = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
- conn = conn
- |> assign(:user, user)
- |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
assert user = json_response(conn, 200)
assert user["header"] != "https://placehold.it/700x335"
Pleroma.Stats.update_stats()
- conn = conn
- |> get("/api/v1/instance")
+ conn =
+ conn
+ |> get("/api/v1/instance")
assert result = json_response(conn, 200)
status = StatusView.render("status.json", %{activity: note})
- created_at = (note.data["object"]["published"] || "")
- |> String.replace(~r/\.\d+Z/, ".000Z")
+ created_at =
+ (note.data["object"]["published"] || "")
+ |> String.replace(~r/\.\d+Z/, ".000Z")
expected = %{
id: to_string(note.id),
test "a reply" do
note = insert(:note_activity)
user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
status = StatusView.render("status.json", %{activity: activity})
import Pleroma.Factory
test "create an authorization token for a valid app" do
- {:ok, app} = Repo.insert(App.register_changeset(%App{}, %{client_name: "client", scopes: "scope", redirect_uris: "url"}))
+ {:ok, app} =
+ Repo.insert(
+ App.register_changeset(%App{}, %{
+ client_name: "client",
+ scopes: "scope",
+ redirect_uris: "url"
+ })
+ )
+
user = insert(:user)
{:ok, auth} = Authorization.create_authorization(app, user)
end
test "use up a token" do
- {:ok, app} = Repo.insert(App.register_changeset(%App{}, %{client_name: "client", scopes: "scope", redirect_uris: "url"}))
+ {:ok, app} =
+ Repo.insert(
+ App.register_changeset(%App{}, %{
+ client_name: "client",
+ scopes: "scope",
+ redirect_uris: "url"
+ })
+ )
+
user = insert(:user)
{:ok, auth} = Authorization.create_authorization(app, user)
expired_auth = %Authorization{
user_id: user.id,
app_id: app.id,
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now, -10),
+ valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -10),
token: "mytoken",
used: false
}
import Pleroma.Factory
test "exchanges a auth token for an access token" do
- {:ok, app} = Repo.insert(App.register_changeset(%App{}, %{client_name: "client", scopes: "scope", redirect_uris: "url"}))
+ {:ok, app} =
+ Repo.insert(
+ App.register_changeset(%App{}, %{
+ client_name: "client",
+ scopes: "scope",
+ redirect_uris: "url"
+ })
+ )
+
user = insert(:user)
{:ok, auth} = Authorization.create_authorization(app, user)
tuple = ActivityRepresenter.to_simple_form(activity, user)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
- assert String.contains?(res, ~s{<link type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748" rel="alternate"/>})
+ assert String.contains?(
+ res,
+ ~s{<link type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748" rel="alternate"/>}
+ )
end
test "a note activity" do
tuple = ActivityRepresenter.to_simple_form(note_activity, user)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
assert clean(res) == clean(expected)
end
answer = %{answer | data: data}
note_object = Object.get_by_ap_id(note.data["object"]["id"])
- Repo.update!(Object.change(note_object, %{ data: Map.put(note_object.data, "external_url", "someurl") }))
+
+ Repo.update!(
+ Object.change(note_object, %{data: Map.put(note_object.data, "external_url", "someurl")})
+ )
user = User.get_cached_by_ap_id(answer.data["actor"])
tuple = ActivityRepresenter.to_simple_form(answer, user)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
assert clean(res) == clean(expected)
end
note_user = User.get_cached_by_ap_id(note.data["actor"])
note = Repo.get(Activity, note.id)
- note_xml = ActivityRepresenter.to_simple_form(note, note_user, true)
- |> :xmerl.export_simple_content(:xmerl_xml)
- |> to_string
+
+ note_xml =
+ ActivityRepresenter.to_simple_form(note, note_user, true)
+ |> :xmerl.export_simple_content(:xmerl_xml)
+ |> to_string
expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:object>
#{note_xml}
</activity:object>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{note.data["actor"]}"/>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{
+ note.data["actor"]
+ }"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
"""
- announce_xml = ActivityRepresenter.to_simple_form(announce, user)
- |> :xmerl.export_simple_content(:xmerl_xml)
- |> to_string
+ announce_xml =
+ ActivityRepresenter.to_simple_form(announce, user)
+ |> :xmerl.export_simple_content(:xmerl_xml)
+ |> to_string
assert clean(expected) == clean(announce_xml)
end
tuple = ActivityRepresenter.to_simple_form(like, user)
refute is_nil(tuple)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
expected = """
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<link ref="#{like.data["context"]}" rel="ostatus:conversation" />
<link rel="self" type="application/atom+xml" href="#{like.data["id"]}"/>
<thr:in-reply-to ref="#{note.data["id"]}" />
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{note.data["actor"]}"/>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{
+ note.data["actor"]
+ }"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
"""
test "a follow activity" do
follower = insert(:user)
followed = insert(:user)
- {:ok, activity} = ActivityPub.insert(%{
- "type" => "Follow",
- "actor" => follower.ap_id,
- "object" => followed.ap_id,
- "to" => [followed.ap_id]
- })
+
+ {:ok, activity} =
+ ActivityPub.insert(%{
+ "type" => "Follow",
+ "actor" => follower.ap_id,
+ "object" => followed.ap_id,
+ "to" => [followed.ap_id]
+ })
tuple = ActivityRepresenter.to_simple_form(activity, follower)
refute is_nil(tuple)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<uri>#{activity.data["object"]}</uri>
</activity:object>
<link rel="self" type="application/atom+xml" href="#{activity.data["id"]}"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{activity.data["object"]}"/>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{
+ activity.data["object"]
+ }"/>
"""
assert clean(res) == clean(expected)
refute is_nil(tuple)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<uri>#{followed.ap_id}</uri>
</activity:object>
<link rel="self" type="application/atom+xml" href="#{activity.data["id"]}"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{followed.ap_id}"/>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{
+ followed.ap_id
+ }"/>
"""
assert clean(res) == clean(expected)
test "a delete" do
user = insert(:user)
- activity = %Activity{data: %{ "id" => "ap_id", "type" => "Delete", "actor" => user.ap_id, "object" => "some_id", "published" => "2017-06-18T12:00:18+00:00" }}
+
+ activity = %Activity{
+ data: %{
+ "id" => "ap_id",
+ "type" => "Delete",
+ "actor" => user.ap_id,
+ "object" => "some_id",
+ "published" => "2017-06-18T12:00:18+00:00"
+ }
+ }
tuple = ActivityRepresenter.to_simple_form(activity, nil)
refute is_nil(tuple)
- res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary
+ res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary()
expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
tuple = FeedRepresenter.to_simple_form(user, [note_activity], [user])
- most_recent_update = note_activity.updated_at
- |> NaiveDateTime.to_iso8601
+ most_recent_update =
+ note_activity.updated_at
+ |> NaiveDateTime.to_iso8601()
res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> to_string
- user_xml = UserRepresenter.to_simple_form(user)
- |> :xmerl.export_simple_content(:xmerl_xml)
- entry_xml = ActivityRepresenter.to_simple_form(note_activity, user)
- |> :xmerl.export_simple_content(:xmerl_xml)
+ user_xml =
+ UserRepresenter.to_simple_form(user)
+ |> :xmerl.export_simple_content(:xmerl_xml)
+
+ entry_xml =
+ ActivityRepresenter.to_simple_form(note_activity, user)
+ |> :xmerl.export_simple_content(:xmerl_xml)
expected = """
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
</entry>
</feed>
"""
+
assert clean(res) == clean(expected)
end
{:ok, like, _object} = Pleroma.Web.ActivityPub.ActivityPub.like(user, object)
- incoming = File.read!("test/fixtures/delete.xml")
- |> String.replace("tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status", note.data["object"]["id"])
+ incoming =
+ File.read!("test/fixtures/delete.xml")
+ |> String.replace(
+ "tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status",
+ note.data["object"]["id"]
+ )
+
{:ok, [delete]} = OStatus.handle_incoming(incoming)
refute Repo.get(Activity, note.id)
test "decodes a salmon", %{conn: conn} do
user = insert(:user)
salmon = File.read!("test/fixtures/salmon.xml")
- conn = conn
- |> put_req_header("content-type", "application/atom+xml")
- |> post("/users/#{user.nickname}/salmon", salmon)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/atom+xml")
+ |> post("/users/#{user.nickname}/salmon", salmon)
assert response(conn, 200)
end
test "decodes a salmon with a changed magic key", %{conn: conn} do
user = insert(:user)
salmon = File.read!("test/fixtures/salmon.xml")
- conn = conn
- |> put_req_header("content-type", "application/atom+xml")
- |> post("/users/#{user.nickname}/salmon", salmon)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/atom+xml")
+ |> post("/users/#{user.nickname}/salmon", salmon)
assert response(conn, 200)
# Set a wrong magic-key for a user so it has to refetch
salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1")
- info = salmon_user.info
- |> Map.put("magic_key", "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB") # Wrong key
+ # Wrong key
+ info =
+ salmon_user.info
+ |> Map.put(
+ "magic_key",
+ "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"
+ )
+
Repo.update(User.info_changeset(salmon_user, %{info: info}))
- conn = build_conn()
- |> put_req_header("content-type", "application/atom+xml")
- |> post("/users/#{user.nickname}/salmon", salmon)
+ conn =
+ build_conn()
+ |> put_req_header("content-type", "application/atom+xml")
+ |> post("/users/#{user.nickname}/salmon", salmon)
assert response(conn, 200)
end
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
- conn = conn
- |> get("/users/#{user.nickname}/feed.atom")
+ conn =
+ conn
+ |> get("/users/#{user.nickname}/feed.atom")
assert response(conn, 200) =~ note_activity.data["object"]["content"]
end
test "gets an object", %{conn: conn} do
note_activity = insert(:note_activity)
user = User.get_by_ap_id(note_activity.data["actor"])
- [_, uuid] = hd Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"])
+ [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"]))
url = "/objects/#{uuid}"
- conn = conn
- |> get(url)
+ conn =
+ conn
+ |> get(url)
- expected = ActivityRepresenter.to_simple_form(note_activity, user, true)
- |> ActivityRepresenter.wrap_with_entry
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+ expected =
+ ActivityRepresenter.to_simple_form(note_activity, user, true)
+ |> ActivityRepresenter.wrap_with_entry()
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
assert response(conn, 200) == expected
end
test "gets an activity", %{conn: conn} do
note_activity = insert(:note_activity)
- [_, uuid] = hd Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])
+ [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
url = "/activities/#{uuid}"
- conn = conn
- |> get(url)
+ conn =
+ conn
+ |> get(url)
assert response(conn, 200)
end
note_activity = insert(:note_activity)
url = "/notice/#{note_activity.id}"
- conn = conn
- |> get(url)
+ conn =
+ conn
+ |> get(url)
assert response(conn, 200)
end
assert user.info["note_count"] == 1
assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
- assert activity.data["object"]["id"] == "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note"
+
+ assert activity.data["object"]["id"] ==
+ "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note"
+
assert activity.data["published"] == "2017-04-23T14:51:03+00:00"
assert activity.data["object"]["published"] == "2017-04-23T14:51:03+00:00"
- assert activity.data["context"] == "tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"
+
+ assert activity.data["context"] ==
+ "tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"
+
assert "http://pleroma.example.org:4000/users/lain3" in activity.data["to"]
- assert activity.data["object"]["emoji"] == %{ "marko" => "marko.png", "reimu" => "reimu.png" }
+ assert activity.data["object"]["emoji"] == %{"marko" => "marko.png", "reimu" => "reimu.png"}
assert activity.local == false
end
test "handle incoming notes - Mastodon, salmon, reply" do
# It uses the context of the replied to object
Repo.insert!(%Object{
- data: %{
- "id" => "https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4",
- "context" => "2hu"
- }})
+ data: %{
+ "id" => "https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4",
+ "context" => "2hu"
+ }
+ })
+
incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211"
- assert activity.data["object"]["content"] == "@<a href=\"https://gs.archae.me/user/4687\" class=\"h-card u-url p-nickname mention\" title=\"shpbot\">shpbot</a> why not indeed."
- assert activity.data["object"]["inReplyTo"] == "tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note"
+
+ assert activity.data["object"]["content"] ==
+ "@<a href=\"https://gs.archae.me/user/4687\" class=\"h-card u-url p-nickname mention\" title=\"shpbot\">shpbot</a> why not indeed."
+
+ assert activity.data["object"]["inReplyTo"] ==
+ "tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note"
+
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
end
incoming = File.read!("test/fixtures/share-gs-local.xml")
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
- incoming = incoming
- |> String.replace("LOCAL_ID", note_activity.data["object"]["id"])
- |> String.replace("LOCAL_USER", user.ap_id)
+
+ incoming =
+ incoming
+ |> String.replace("LOCAL_ID", note_activity.data["object"]["id"])
+ |> String.replace("LOCAL_USER", user.ap_id)
{:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Announce"
assert activity.data["actor"] == "https://mastodon.social/users/lambadalambda"
assert activity.data["object"] == retweeted_activity.data["object"]["id"]
- assert activity.data["id"] == "tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status"
+
+ assert activity.data["id"] ==
+ "tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status"
refute activity.local
assert retweeted_activity.data["type"] == "Create"
end
test "handle incoming favorites - GS, websub" do
- capture_log fn ->
+ capture_log(fn ->
incoming = File.read!("test/fixtures/favorite.xml")
{:ok, [[activity, favorited_activity]]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Like"
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"] == favorited_activity.data["object"]["id"]
- assert activity.data["id"] == "tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00"
+
+ assert activity.data["id"] ==
+ "tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00"
refute activity.local
assert favorited_activity.data["type"] == "Create"
assert favorited_activity.data["actor"] == "https://shitposter.club/user/1"
- assert favorited_activity.data["object"]["id"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+
+ assert favorited_activity.data["object"]["id"] ==
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+
refute favorited_activity.local
- end
+ end)
end
test "handle conversation references" do
incoming = File.read!("test/fixtures/mastodon_conversation.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- assert activity.data["context"] == "tag:mastodon.social,2017-08-28:objectId=7876885:objectType=Conversation"
+ assert activity.data["context"] ==
+ "tag:mastodon.social,2017-08-28:objectId=7876885:objectType=Conversation"
end
test "handle incoming favorites with locally available object - GS, websub" do
note_activity = insert(:note_activity)
- incoming = File.read!("test/fixtures/favorite_with_local_note.xml")
- |> String.replace("localid", note_activity.data["object"]["id"])
+ incoming =
+ File.read!("test/fixtures/favorite_with_local_note.xml")
+ |> String.replace("localid", note_activity.data["object"]["id"])
{:ok, [[activity, favorited_activity]]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
- assert activity.data["object"]["inReplyTo"] == "http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"
+
+ assert activity.data["object"]["inReplyTo"] ==
+ "http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"
+
assert "http://pleroma.example.org:4000/users/lain5" in activity.data["to"]
- assert activity.data["object"]["id"] == "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note"
+
+ assert activity.data["object"]["id"] ==
+ "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note"
+
assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
end
incoming = File.read!("test/fixtures/follow.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
assert activity.data["type"] == "Follow"
- assert activity.data["id"] == "tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00"
+
+ assert activity.data["id"] ==
+ "tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00"
+
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"] == "https://pawoo.net/users/pekorino"
refute activity.local
expected = %{
"hub" => "https://social.heldscal.la/main/push/hub",
- "magic_key" => "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
+ "magic_key" =>
+ "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
"name" => "shp",
"nickname" => "shp",
"salmon" => "https://social.heldscal.la/main/salmon/user/29191",
"host" => "social.heldscal.la",
"fqn" => user,
"bio" => "cofe",
- "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]},
+ "avatar" => %{
+ "type" => "Image",
+ "url" => [
+ %{
+ "href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg",
+ "mediaType" => "image/jpeg",
+ "type" => "Link"
+ }
+ ]
+ },
"subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}",
"ap_id" => nil
}
+
assert data == expected
end
expected = %{
"hub" => "https://social.heldscal.la/main/push/hub",
- "magic_key" => "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
+ "magic_key" =>
+ "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
"name" => "shp",
"nickname" => "shp",
"salmon" => "https://social.heldscal.la/main/salmon/user/29191",
"host" => "social.heldscal.la",
"fqn" => user,
"bio" => "cofe",
- "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]},
+ "avatar" => %{
+ "type" => "Image",
+ "url" => [
+ %{
+ "href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg",
+ "mediaType" => "image/jpeg",
+ "type" => "Link"
+ }
+ ]
+ },
"subscribe_address" => "https://social.heldscal.la/main/ostatussub?profile={uri}",
"ap_id" => nil
}
+
assert data == expected
end
end
describe "fetching a status by it's HTML url" do
test "it builds a missing status from an html url" do
- capture_log fn ->
+ capture_log(fn ->
url = "https://shitposter.club/notice/2827873"
- {:ok, [activity] } = OStatus.fetch_activity_from_url(url)
+ {:ok, [activity]} = OStatus.fetch_activity_from_url(url)
assert activity.data["actor"] == "https://shitposter.club/user/1"
- assert activity.data["object"]["id"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
- end
+
+ assert activity.data["object"]["id"] ==
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ end)
end
test "it works for atom notes, too" do
url = "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056"
- {:ok, [activity] } = OStatus.fetch_activity_from_url(url)
+ {:ok, [activity]} = OStatus.fetch_activity_from_url(url)
assert activity.data["actor"] == "https://social.sakamoto.gq/users/eal"
assert activity.data["object"]["id"] == url
end
incoming = File.read!("test/fixtures/nil_mention_entry.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- assert activity.data["to"] == ["http://localhost:4001/users/atarifrosch@social.stopwatchingus-heidelberg.de/followers", "https://www.w3.org/ns/activitystreams#Public"]
+ assert activity.data["to"] == [
+ "http://localhost:4001/users/atarifrosch@social.stopwatchingus-heidelberg.de/followers",
+ "https://www.w3.org/ns/activitystreams#Public"
+ ]
end
end
end
test "generates an RSA private key pem" do
- {:ok, key} = Salmon.generate_rsa_pem
+ {:ok, key} = Salmon.generate_rsa_pem()
assert is_binary(key)
assert Regex.match?(~r/RSA/, key)
end
salmon = File.read!("test/fixtures/salmon2.xml")
{:ok, key} = Salmon.fetch_magic_key(salmon)
- assert key == "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB"
+ assert key ==
+ "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB"
end
test "it pushes an activity to remote accounts it's addressed to" do
mentioned_user = insert(:user, user_data)
note = insert(:note)
+
activity_data = %{
- "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id,
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"] ++ [mentioned_user.ap_id],
"object" => note.data,
- "published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
+ "published_at" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => note.data["context"]
}
user = Repo.get_by(User, ap_id: activity.data["actor"])
{:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
- poster = fn (url, _data, _headers, _options) ->
+ poster = fn url, _data, _headers, _options ->
assert url == "http://example.org/salmon"
end
+
Salmon.publish(user, activity, poster)
end
end
{:ok, announce_activity, _object} = ActivityPub.announce(user, object)
note_activity = Activity.get_by_ap_id(note_activity.data["id"])
- status = ActivityRepresenter.to_map(announce_activity, %{users: [user, activity_actor], announced_activity: note_activity, for: user})
+ status =
+ ActivityRepresenter.to_map(announce_activity, %{
+ users: [user, activity_actor],
+ announced_activity: note_activity,
+ for: user
+ })
assert status["id"] == announce_activity.id
assert status["user"] == UserView.render("show.json", %{user: user, for: user})
- retweeted_status = ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user})
+ retweeted_status =
+ ActivityRepresenter.to_map(note_activity, %{user: activity_actor, for: user})
+
assert retweeted_status["repeated"] == true
assert retweeted_status["id"] == note_activity.id
assert status["statusnet_conversation_id"] == retweeted_status["statusnet_conversation_id"]
object = Object.get_by_ap_id(note_activity.data["object"]["id"])
{:ok, like_activity, _object} = ActivityPub.like(user, object)
- status = ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity})
+
+ status =
+ ActivityRepresenter.to_map(like_activity, %{user: user, liked_activity: note_activity})
assert status["id"] == like_activity.id
assert status["in_reply_to_status_id"] == note_activity.id
end
test "an activity" do
- {:ok, user} = UserBuilder.insert
+ {:ok, user} = UserBuilder.insert()
# {:ok, mentioned_user } = UserBuilder.insert(%{nickname: "shp", ap_id: "shp"})
mentioned_user = insert(:user, %{nickname: "shp"})
}
}
- content_html = "<script>alert('YAY')</script>Some :2hu: content mentioning <a href='#{mentioned_user.ap_id}'>@shp</shp>"
+ content_html =
+ "<script>alert('YAY')</script>Some :2hu: content mentioning <a href='#{mentioned_user.ap_id}'>@shp</shp>"
+
content = HtmlSanitizeEx.strip_tags(content_html)
- date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601
+ date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601()
+
+ {:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert()
- {:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert
to = [
User.ap_followers(user),
"https://www.w3.org/ns/activitystreams#Public",
mentioned_user.ap_id
]
+
activity = %Activity{
id: 1,
data: %{
"type" => "Note",
"content" => content_html,
"summary" => "2hu",
- "inReplyToStatusId" => 213123,
+ "inReplyToStatusId" => 213_123,
"attachment" => [
object
],
recipients: to
}
- expected_html = "<span>2hu</span><br />alert('YAY')Some <img height='32px' width='32px' alt='2hu' title='2hu' src='corndog.png' /> content mentioning <a href=\"#{mentioned_user.ap_id}\">@shp</a>"
+ expected_html =
+ "<span>2hu</span><br />alert('YAY')Some <img height='32px' width='32px' alt='2hu' title='2hu' src='corndog.png' /> content mentioning <a href=\"#{
+ mentioned_user.ap_id
+ }\">@shp</a>"
expected_status = %{
"id" => activity.id,
"text" => "2hu" <> content,
"is_post_verb" => true,
"created_at" => "Tue May 24 13:26:08 +0000 2016",
- "in_reply_to_status_id" => 213123,
+ "in_reply_to_status_id" => 213_123,
"statusnet_conversation_id" => convo_object.id,
"attachments" => [
ObjectRepresenter.to_map(object)
"uri" => activity.data["object"]["id"]
}
- assert ActivityRepresenter.to_map(activity, %{user: user, for: follower, mentioned: [mentioned_user]}) == expected_status
+ assert ActivityRepresenter.to_map(activity, %{
+ user: user,
+ for: follower,
+ mentioned: [mentioned_user]
+ }) == expected_status
end
test "an undo for a follow" do
id: nil,
data: %{
"mediaType" => "image/png",
- "name" => "blabla", "type" => "Document",
- "url" => "http://mastodon.example.org/system/media_attachments/files/000/000/001/original/8619f31c6edec470.png"
+ "name" => "blabla",
+ "type" => "Document",
+ "url" =>
+ "http://mastodon.example.org/system/media_attachments/files/000/000/001/original/8619f31c6edec470.png"
}
}
expected_object = %{
- url: "http://mastodon.example.org/system/media_attachments/files/000/000/001/original/8619f31c6edec470.png",
+ url:
+ "http://mastodon.example.org/system/media_attachments/files/000/000/001/original/8619f31c6edec470.png",
mimetype: "image/png",
oembed: false,
id: nil
describe "POST /api/account/verify_credentials" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/account/verify_credentials.json"
+ conn = post(conn, "/api/account/verify_credentials.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: user} do
- conn = conn
+ conn =
+ conn
|> with_credentials(user.nickname, "test")
|> post("/api/account/verify_credentials.json")
describe "POST /api/account/most_recent_notification" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/account/most_recent_notification.json"
+ conn = post(conn, "/api/account/most_recent_notification.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: user} do
- conn = conn
+ conn =
+ conn
|> with_credentials(user.nickname, "test")
|> post("/api/account/most_recent_notification.json", %{id: "200"})
describe "POST /statuses/update.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/statuses/update.json"
+ conn = post(conn, "/api/statuses/update.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
conn_with_creds = conn |> with_credentials(user.nickname, "test")
request_path = "/api/statuses/update.json"
- error_response = %{"request" => request_path,
- "error" => "Client must provide a 'status' parameter with a value."}
+ error_response = %{
+ "request" => request_path,
+ "error" => "Client must provide a 'status' parameter with a value."
+ }
+
conn = conn_with_creds |> post(request_path)
assert json_response(conn, 400) == error_response
- conn = conn_with_creds |> post(request_path, %{ status: "" })
+ conn = conn_with_creds |> post(request_path, %{status: ""})
assert json_response(conn, 400) == error_response
- conn = conn_with_creds |> post(request_path, %{ status: " " })
+ conn = conn_with_creds |> post(request_path, %{status: " "})
assert json_response(conn, 400) == error_response
- conn = conn_with_creds |> post(request_path, %{ status: "Nice meme." })
- assert json_response(conn, 200) == ActivityRepresenter.to_map(Repo.one(Activity), %{user: user})
+ conn = conn_with_creds |> post(request_path, %{status: "Nice meme."})
+
+ assert json_response(conn, 200) ==
+ ActivityRepresenter.to_map(Repo.one(Activity), %{user: user})
end
end
describe "GET /statuses/public_timeline.json" do
test "returns statuses", %{conn: conn} do
- {:ok, user} = UserBuilder.insert
+ {:ok, user} = UserBuilder.insert()
activities = ActivityBuilder.insert_list(30, %{}, %{user: user})
ActivityBuilder.insert_list(10, %{}, %{user: user})
since_id = List.last(activities).id
- conn = conn
+ conn =
+ conn
|> get("/api/statuses/public_timeline.json", %{since_id: since_id})
response = json_response(conn, 200)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Hey!"})
actor = Repo.get_by!(User, ap_id: activity.data["actor"])
- conn = conn
- |> get("/api/statuses/show/#{activity.id}.json")
+ conn =
+ conn
+ |> get("/api/statuses/show/#{activity.id}.json")
response = json_response(conn, 200)
test "gets user with screen_name", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> get("/api/users/show.json", %{"screen_name" => user.nickname})
+ conn =
+ conn
+ |> get("/api/users/show.json", %{"screen_name" => user.nickname})
response = json_response(conn, 200)
test "gets user with user_id", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> get("/api/users/show.json", %{"user_id" => user.id})
+ conn =
+ conn
+ |> get("/api/users/show.json", %{"user_id" => user.id})
response = json_response(conn, 200)
{:ok, logged_in, user, _activity} = TwitterAPI.follow(logged_in, %{"user_id" => user.id})
- conn = conn
- |> with_credentials(logged_in.nickname, "test")
- |> get("/api/users/show.json", %{"user_id" => user.id})
+ conn =
+ conn
+ |> with_credentials(logged_in.nickname, "test")
+ |> get("/api/users/show.json", %{"user_id" => user.id})
response = json_response(conn, 200)
describe "GET /statusnet/conversation/:id.json" do
test "returns the statuses in the conversation", %{conn: conn} do
- {:ok, _user} = UserBuilder.insert
+ {:ok, _user} = UserBuilder.insert()
{:ok, _activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
{:ok, _activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
{:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
- {:ok, object} = Object.context_mapping("2hu") |> Repo.insert
- conn = conn
- |> get("/api/statusnet/conversation/#{object.id}.json")
+ {:ok, object} = Object.context_mapping("2hu") |> Repo.insert()
+
+ conn =
+ conn
+ |> get("/api/statusnet/conversation/#{object.id}.json")
response = json_response(conn, 200)
describe "GET /statuses/friends_timeline.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = get conn, "/api/statuses/friends_timeline.json"
+ conn = get(conn, "/api/statuses/friends_timeline.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
user = insert(:user)
- activities = ActivityBuilder.insert_list(30, %{"to" => [User.ap_followers(user)]}, %{user: user})
- returned_activities = ActivityBuilder.insert_list(10, %{"to" => [User.ap_followers(user)]}, %{user: user})
+
+ activities =
+ ActivityBuilder.insert_list(30, %{"to" => [User.ap_followers(user)]}, %{user: user})
+
+ returned_activities =
+ ActivityBuilder.insert_list(10, %{"to" => [User.ap_followers(user)]}, %{user: user})
+
other_user = insert(:user)
ActivityBuilder.insert_list(10, %{}, %{user: other_user})
since_id = List.last(activities).id
- current_user = Ecto.Changeset.change(current_user, following: [User.ap_followers(user)]) |> Repo.update!
+ current_user =
+ Ecto.Changeset.change(current_user, following: [User.ap_followers(user)])
+ |> Repo.update!()
- conn = conn
+ conn =
+ conn
|> with_credentials(current_user.nickname, "test")
|> get("/api/statuses/friends_timeline.json", %{since_id: since_id})
response = json_response(conn, 200)
assert length(response) == 10
- assert response == Enum.map(returned_activities, fn (activity) -> ActivityRepresenter.to_map(activity, %{user: User.get_cached_by_ap_id(activity.data["actor"]), for: current_user}) end)
+
+ assert response ==
+ Enum.map(returned_activities, fn activity ->
+ ActivityRepresenter.to_map(activity, %{
+ user: User.get_cached_by_ap_id(activity.data["actor"]),
+ for: current_user
+ })
+ end)
end
end
describe "GET /statuses/mentions.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = get conn, "/api/statuses/mentions.json"
+ conn = get(conn, "/api/statuses/mentions.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
- {:ok, activity} = ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
+ {:ok, activity} =
+ ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
- conn = conn
+ conn =
+ conn
|> with_credentials(current_user.nickname, "test")
|> get("/api/statuses/mentions.json")
response = json_response(conn, 200)
assert length(response) == 1
- assert Enum.at(response, 0) == ActivityRepresenter.to_map(activity, %{user: current_user, mentioned: [current_user]})
+
+ assert Enum.at(response, 0) ==
+ ActivityRepresenter.to_map(activity, %{
+ user: current_user,
+ mentioned: [current_user]
+ })
end
end
describe "GET /statuses/user_timeline.json" do
setup [:valid_user]
+
test "without any params", %{conn: conn} do
conn = get(conn, "/api/statuses/user_timeline.json")
- assert json_response(conn, 400) == %{"error" => "You need to specify screen_name or user_id", "request" => "/api/statuses/user_timeline.json"}
+
+ assert json_response(conn, 400) == %{
+ "error" => "You need to specify screen_name or user_id",
+ "request" => "/api/statuses/user_timeline.json"
+ }
end
test "with user_id", %{conn: conn} do
test "with credentials", %{conn: conn, user: current_user} do
{:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: current_user})
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> get("/api/statuses/user_timeline.json")
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/statuses/user_timeline.json")
response = json_response(conn, 200)
test "with credentials with user_id", %{conn: conn, user: current_user} do
user = insert(:user)
{:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/statuses/user_timeline.json", %{"user_id" => user.id})
response = json_response(conn, 200)
test "with credentials screen_name", %{conn: conn, user: current_user} do
user = insert(:user)
{:ok, activity} = ActivityBuilder.insert(%{"id" => 1}, %{user: user})
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> get("/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> get("/api/statuses/user_timeline.json", %{"screen_name" => user.nickname})
response = json_response(conn, 200)
describe "POST /friendships/create.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/friendships/create.json"
+ conn = post(conn, "/api/friendships/create.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
followed = insert(:user)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/friendships/create.json", %{user_id: followed.id})
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/friendships/create.json", %{user_id: followed.id})
current_user = Repo.get(User, current_user.id)
assert User.ap_followers(followed) in current_user.following
- assert json_response(conn, 200) == UserView.render("show.json", %{user: followed, for: current_user})
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: followed, for: current_user})
end
end
describe "POST /friendships/destroy.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/friendships/destroy.json"
+ conn = post(conn, "/api/friendships/destroy.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
assert User.ap_followers(followed) in current_user.following
ActivityPub.follow(current_user, followed)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/friendships/destroy.json", %{user_id: followed.id})
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/friendships/destroy.json", %{user_id: followed.id})
current_user = Repo.get(User, current_user.id)
assert current_user.following == [current_user.ap_id]
- assert json_response(conn, 200) == UserView.render("show.json", %{user: followed, for: current_user})
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: followed, for: current_user})
end
end
describe "POST /blocks/create.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/blocks/create.json"
+ conn = post(conn, "/api/blocks/create.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
blocked = insert(:user)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/blocks/create.json", %{user_id: blocked.id})
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/blocks/create.json", %{user_id: blocked.id})
current_user = Repo.get(User, current_user.id)
assert User.blocks?(current_user, blocked)
- assert json_response(conn, 200) == UserView.render("show.json", %{user: blocked, for: current_user})
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: blocked, for: current_user})
end
end
describe "POST /blocks/destroy.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/blocks/destroy.json"
+ conn = post(conn, "/api/blocks/destroy.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
{:ok, current_user} = User.block(current_user, blocked)
assert User.blocks?(current_user, blocked)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
current_user = Repo.get(User, current_user.id)
assert current_user.info["blocks"] == []
- assert json_response(conn, 200) == UserView.render("show.json", %{user: blocked, for: current_user})
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: blocked, for: current_user})
end
end
describe "GET /help/test.json" do
test "returns \"ok\"", %{conn: conn} do
- conn = get conn, "/api/help/test.json"
+ conn = get(conn, "/api/help/test.json")
assert json_response(conn, 200) == "ok"
end
end
describe "POST /api/qvitter/update_avatar.json" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
- conn = post conn, "/api/qvitter/update_avatar.json"
+ conn = post(conn, "/api/qvitter/update_avatar.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
avatar_image = File.read!("test/fixtures/avatar_data_uri")
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
+
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
current_user = Repo.get(User, current_user.id)
assert is_map(current_user.avatar)
- assert json_response(conn, 200) == UserView.render("show.json", %{user: current_user, for: current_user})
+
+ assert json_response(conn, 200) ==
+ UserView.render("show.json", %{user: current_user, for: current_user})
end
end
describe "POST /api/favorites/create/:id" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
note_activity = insert(:note_activity)
- conn = post conn, "/api/favorites/create/#{note_activity.id}.json"
+ conn = post(conn, "/api/favorites/create/#{note_activity.id}.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
test "with credentials", %{conn: conn, user: current_user} do
note_activity = insert(:note_activity)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/favorites/create/#{note_activity.id}.json")
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/favorites/create/#{note_activity.id}.json")
assert json_response(conn, 200)
end
describe "POST /api/favorites/destroy/:id" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
note_activity = insert(:note_activity)
- conn = post conn, "/api/favorites/destroy/#{note_activity.id}.json"
+ conn = post(conn, "/api/favorites/destroy/#{note_activity.id}.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
object = Object.get_by_ap_id(note_activity.data["object"]["id"])
ActivityPub.like(current_user, object)
- conn = conn
- |> with_credentials(current_user.nickname, "test")
- |> post("/api/favorites/destroy/#{note_activity.id}.json")
+ conn =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post("/api/favorites/destroy/#{note_activity.id}.json")
assert json_response(conn, 200)
end
describe "POST /api/statuses/retweet/:id" do
setup [:valid_user]
+
test "without valid credentials", %{conn: conn} do
note_activity = insert(:note_activity)
- conn = post conn, "/api/statuses/retweet/#{note_activity.id}.json"
+ conn = post(conn, "/api/statuses/retweet/#{note_activity.id}.json")
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
end
request_path = "/api/statuses/retweet/#{note_activity.id}.json"
- response = conn
- |> with_credentials(current_user.nickname, "test")
- |> post(request_path)
+ response =
+ conn
+ |> with_credentials(current_user.nickname, "test")
+ |> post(request_path)
+
activity = Repo.get(Activity, note_activity.id)
activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
- assert json_response(response, 200) == ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user})
+
+ assert json_response(response, 200) ==
+ ActivityRepresenter.to_map(activity, %{user: activity_user, for: current_user})
end
end
"confirm" => "bear"
}
- conn = conn
- |> post("/api/account/register", data)
+ conn =
+ conn
+ |> post("/api/account/register", data)
user = json_response(conn, 200)
"confirm" => "bear"
}
- conn = conn
- |> post("/api/account/register", data)
+ conn =
+ conn
+ |> post("/api/account/register", data)
errors = json_response(conn, 400)
user = insert(:user)
other_user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/externalprofile/show", %{profileurl: other_user.ap_id})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/externalprofile/show", %{profileurl: other_user.ap_id})
assert json_response(conn, 200) == UserView.render("show.json", %{user: other_user})
end
{:ok, follower_one} = User.follow(follower_one, user)
{:ok, follower_two} = User.follow(follower_two, user)
- conn = conn
- |> assign(:user, user)
- |> get("/api/statuses/followers")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/statuses/followers")
- assert json_response(conn, 200) == UserView.render("index.json", %{users: [follower_one, follower_two], for: user})
+ assert json_response(conn, 200) ==
+ UserView.render("index.json", %{users: [follower_one, follower_two], for: user})
end
end
{:ok, user} = User.follow(user, followed_one)
{:ok, user} = User.follow(user, followed_two)
- conn = conn
- |> assign(:user, user)
- |> get("/api/statuses/friends")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/statuses/friends")
- assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
+ assert MapSet.equal?(
+ MapSet.new(json_response(conn, 200)),
+ MapSet.new(
+ UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
+ )
+ )
end
test "it returns a given user's friends with user_id", %{conn: conn} do
{:ok, user} = User.follow(user, followed_one)
{:ok, user} = User.follow(user, followed_two)
- conn = conn
- |> get("/api/statuses/friends", %{"user_id" => user.id})
+ conn =
+ conn
+ |> get("/api/statuses/friends", %{"user_id" => user.id})
- assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
+ assert MapSet.equal?(
+ MapSet.new(json_response(conn, 200)),
+ MapSet.new(
+ UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
+ )
+ )
end
test "it returns a given user's friends with screen_name", %{conn: conn} do
{:ok, user} = User.follow(user, followed_one)
{:ok, user} = User.follow(user, followed_two)
- conn = conn
- |> get("/api/statuses/friends", %{"screen_name" => user.nickname})
+ conn =
+ conn
+ |> get("/api/statuses/friends", %{"screen_name" => user.nickname})
- assert MapSet.equal?(MapSet.new(json_response(conn, 200)), MapSet.new(UserView.render("index.json", %{users: [followed_one, followed_two], for: user})))
+ assert MapSet.equal?(
+ MapSet.new(json_response(conn, 200)),
+ MapSet.new(
+ UserView.render("index.json", %{users: [followed_one, followed_two], for: user})
+ )
+ )
end
end
{:ok, user} = User.follow(user, followed_one)
{:ok, user} = User.follow(user, followed_two)
- conn = conn
- |> assign(:user, user)
- |> get("/api/friends/ids")
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/friends/ids")
expected = [followed_one.id, followed_two.id]
- assert MapSet.equal?(MapSet.new(Poison.decode!(json_response(conn, 200))), MapSet.new(expected))
+
+ assert MapSet.equal?(
+ MapSet.new(Poison.decode!(json_response(conn, 200))),
+ MapSet.new(expected)
+ )
end
end
test "it updates a user's profile", %{conn: conn} do
user = insert(:user)
- conn = conn
- |> assign(:user, user)
- |> post("/api/account/update_profile.json", %{"name" => "new name", "description" => "new description"})
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/account/update_profile.json", %{
+ "name" => "new name",
+ "description" => "new description"
+ })
user = Repo.get!(User, user.id)
assert user.name == "new name"
{:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
{:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
- conn = conn
- |> get("/api/search.json", %{"q" => "2hu", "page" => "1", "rpp" => "1"})
+ conn =
+ conn
+ |> get("/api/search.json", %{"q" => "2hu", "page" => "1", "rpp" => "1"})
assert [status] = json_response(conn, 200)
assert status["id"] == activity.id
{:ok, activity} = CommonAPI.post(user, %{"status" => "This is about #2hu"})
{:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
- conn = conn
- |> get("/api/statusnet/tags/timeline/2hu.json")
+ conn =
+ conn
+ |> get("/api/statusnet/tags/timeline/2hu.json")
assert [status] = json_response(conn, 200)
assert status["id"] == activity.id
object = Repo.insert!(%Object{data: object_data})
input = %{
- "status" => "Hello again, @shp.<script></script>\nThis is on another :moominmamma: line. #2hu #epic #phantasmagoric",
+ "status" =>
+ "Hello again, @shp.<script></script>\nThis is on another :moominmamma: line. #2hu #epic #phantasmagoric",
"media_ids" => [object.id]
}
- { :ok, activity = %Activity{} } = TwitterAPI.create_status(user, input)
+ {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
+
+ expected_text =
+ "Hello again, <span><a href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :moominmamma: line. <a href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>"
- expected_text = "Hello again, <span><a href='shp'>@<span>shp</span></a></span>.<script></script><br>This is on another :moominmamma: line. <a href='http://localhost:4001/tag/2hu' rel='tag'>#2hu</a> <a href='http://localhost:4001/tag/epic' rel='tag'>#epic</a> <a href='http://localhost:4001/tag/phantasmagoric' rel='tag'>#phantasmagoric</a><br><a href=\"http://example.org/image.jpg\" class='attachment'>image.jpg</a>"
assert get_in(activity.data, ["object", "content"]) == expected_text
assert get_in(activity.data, ["object", "type"]) == "Note"
assert get_in(activity.data, ["object", "actor"]) == user.ap_id
assert get_in(activity.data, ["actor"]) == user.ap_id
assert Enum.member?(get_in(activity.data, ["cc"]), User.ap_followers(user))
- assert Enum.member?(get_in(activity.data, ["to"]), "https://www.w3.org/ns/activitystreams#Public")
+
+ assert Enum.member?(
+ get_in(activity.data, ["to"]),
+ "https://www.w3.org/ns/activitystreams#Public"
+ )
+
assert Enum.member?(get_in(activity.data, ["cc"]), "shp")
assert activity.local == true
- assert %{"moominmamma" => "http://localhost:4001/finmoji/128px/moominmamma-128.png"} = activity.data["object"]["emoji"]
+ assert %{"moominmamma" => "http://localhost:4001/finmoji/128px/moominmamma-128.png"} =
+ activity.data["object"]["emoji"]
# hashtags
assert activity.data["object"]["tag"] == ["2hu", "epic", "phantasmagoric"]
test "create a status that is a reply" do
user = insert(:user)
+
input = %{
"status" => "Hello again."
}
- { :ok, activity = %Activity{} } = TwitterAPI.create_status(user, input)
+ {:ok, activity = %Activity{}} = TwitterAPI.create_status(user, input)
input = %{
"status" => "Here's your (you).",
"in_reply_to_status_id" => activity.id
}
- { :ok, reply = %Activity{} } = TwitterAPI.create_status(user, input)
+ {:ok, reply = %Activity{}} = TwitterAPI.create_status(user, input)
assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"])
- assert get_in(reply.data, ["object", "context"]) == get_in(activity.data, ["object", "context"])
+
+ assert get_in(reply.data, ["object", "context"]) ==
+ get_in(activity.data, ["object", "context"])
+
assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"])
assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id
end
test "fetch public statuses, excluding remote ones." do
- %{ public: activity, user: user } = ActivityBuilder.public_and_non_public
+ %{public: activity, user: user} = ActivityBuilder.public_and_non_public()
insert(:note_activity, %{local: false})
follower = insert(:user, following: [User.ap_followers(user)])
statuses = TwitterAPI.fetch_public_statuses(follower)
assert length(statuses) == 1
- assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: user, for: follower})
+
+ assert Enum.at(statuses, 0) ==
+ ActivityRepresenter.to_map(activity, %{user: user, for: follower})
end
test "fetch whole known network statuses" do
- %{ public: activity, user: user } = ActivityBuilder.public_and_non_public
+ %{public: activity, user: user} = ActivityBuilder.public_and_non_public()
insert(:note_activity, %{local: false})
follower = insert(:user, following: [user.follower_address])
statuses = TwitterAPI.fetch_public_and_external_statuses(follower)
assert length(statuses) == 2
- assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: user, for: follower})
+
+ assert Enum.at(statuses, 0) ==
+ ActivityRepresenter.to_map(activity, %{user: user, for: follower})
end
test "fetch friends' statuses" do
assert length(statuses) == 2
assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: activity_user})
- assert Enum.at(statuses, 1) == ActivityRepresenter.to_map(direct_activity, %{user: direct_activity_user, mentioned: [user]})
+
+ assert Enum.at(statuses, 1) ==
+ ActivityRepresenter.to_map(direct_activity, %{
+ user: direct_activity_user,
+ mentioned: [user]
+ })
end
test "fetch user's mentions" do
statuses = TwitterAPI.fetch_mentions(user)
assert length(statuses) == 1
- assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: activity_user, mentioned: [user]})
+
+ assert Enum.at(statuses, 0) ==
+ ActivityRepresenter.to_map(activity, %{user: activity_user, mentioned: [user]})
end
test "get a user by params" do
user1_result = {:ok, user1} = UserBuilder.insert(%{ap_id: "some id", email: "test@pleroma"})
- {:ok, user2} = UserBuilder.insert(%{ap_id: "some other id", nickname: "testname2", email: "test2@pleroma"})
+
+ {:ok, user2} =
+ UserBuilder.insert(%{ap_id: "some other id", nickname: "testname2", email: "test2@pleroma"})
assert {:error, "You need to specify screen_name or user_id"} == TwitterAPI.get_user(nil, nil)
assert user1_result == TwitterAPI.get_user(nil, %{"user_id" => user1.id})
assert user1_result == TwitterAPI.get_user(user1, nil)
assert user1_result == TwitterAPI.get_user(user2, %{"user_id" => user1.id})
assert user1_result == TwitterAPI.get_user(user2, %{"screen_name" => user1.nickname})
- assert {:error, "No user with such screen_name"} == TwitterAPI.get_user(nil, %{"screen_name" => "Satan"})
+
+ assert {:error, "No user with such screen_name"} ==
+ TwitterAPI.get_user(nil, %{"screen_name" => "Satan"})
+
assert {:error, "No user with such user_id"} == TwitterAPI.get_user(nil, %{"user_id" => 666})
end
test "fetch user's statuses" do
{:ok, user1} = UserBuilder.insert(%{ap_id: "some id", email: "test@pleroma"})
- {:ok, user2} = UserBuilder.insert(%{ap_id: "some other id", nickname: "testname2", email: "test2@pleroma"})
+
+ {:ok, user2} =
+ UserBuilder.insert(%{ap_id: "some other id", nickname: "testname2", email: "test2@pleroma"})
{:ok, status1} = ActivityBuilder.insert(%{"id" => 1}, %{user: user1})
{:ok, status2} = ActivityBuilder.insert(%{"id" => 2}, %{user: user2})
user = insert(:user)
followed = insert(:user)
- {:ok, user, followed, _activity } = TwitterAPI.follow(user, %{"user_id" => followed.id})
+ {:ok, user, followed, _activity} = TwitterAPI.follow(user, %{"user_id" => followed.id})
assert User.ap_followers(followed) in user.following
- { :error, msg } = TwitterAPI.follow(user, %{"user_id" => followed.id})
+ {:error, msg} = TwitterAPI.follow(user, %{"user_id" => followed.id})
assert msg == "Could not follow user: #{followed.nickname} is already on your list."
end
user = insert(:user)
followed = insert(:user)
- {:ok, user, followed, _activity } = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
+ {:ok, user, followed, _activity} =
+ TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
+
assert User.ap_followers(followed) in user.following
followed = User.get_by_ap_id(followed.ap_id)
assert followed.info["follower_count"] == 1
- { :error, msg } = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
+ {:error, msg} = TwitterAPI.follow(user, %{"screen_name" => followed.nickname})
assert msg == "Could not follow user: #{followed.nickname} is already on your list."
end
user = insert(:user, %{following: [User.ap_followers(unfollowed)]})
ActivityPub.follow(user, unfollowed)
- {:ok, user, unfollowed } = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
+ {:ok, user, unfollowed} = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
assert user.following == []
- { :error, msg } = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
+ {:error, msg} = TwitterAPI.unfollow(user, %{"user_id" => unfollowed.id})
assert msg == "Not subscribed!"
end
ActivityPub.follow(user, unfollowed)
- {:ok, user, unfollowed } = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
+ {:ok, user, unfollowed} = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
assert user.following == []
- { :error, msg } = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
+ {:error, msg} = TwitterAPI.unfollow(user, %{"screen_name" => unfollowed.nickname})
assert msg == "Not subscribed!"
end
{:ok, activity_two} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
{:ok, _activity_three} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
- {:ok, object} = Object.context_mapping("2hu") |> Repo.insert
+ {:ok, object} = Object.context_mapping("2hu") |> Repo.insert()
statuses = TwitterAPI.fetch_conversation(user, object.id)
end
test "upload a file" do
- file = %Plug.Upload{content_type: "image/jpg", path: Path.absname("test/fixtures/image.jpg"), filename: "an_image.jpg"}
+ file = %Plug.Upload{
+ content_type: "image/jpg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ filename: "an_image.jpg"
+ }
response = TwitterAPI.upload(file)
{:ok, status} = TwitterAPI.fav(user, note_activity.id)
updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
- assert status == ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})
+ assert status ==
+ ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})
end
test "it unfavorites a status, returns the updated status" do
activity_user = Repo.get_by!(User, ap_id: note_activity.data["actor"])
object = Object.get_by_ap_id(note_activity.data["object"]["id"])
- {:ok, _like_activity, _object } = ActivityPub.like(user, object)
+ {:ok, _like_activity, _object} = ActivityPub.like(user, object)
updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
- assert ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})["fave_num"] == 1
+
+ assert ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})[
+ "fave_num"
+ ] == 1
{:ok, status} = TwitterAPI.unfav(user, note_activity.id)
{:ok, status} = TwitterAPI.repeat(user, note_activity.id)
updated_activity = Activity.get_by_ap_id(note_activity.data["id"])
- assert status == ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})
+ assert status ==
+ ActivityRepresenter.to_map(updated_activity, %{user: activity_user, for: user})
end
test "it registers a new user and returns the user." do
{:ok, user} = TwitterAPI.register_user(data)
fetched_user = Repo.get_by(User, nickname: "lain")
- assert UserView.render("show.json", %{user: user}) == UserView.render("show.json", %{user: fetched_user})
+
+ assert UserView.render("show.json", %{user: user}) ==
+ UserView.render("show.json", %{user: fetched_user})
end
test "it returns the error on registration problems" do
end
test "returns an existing mapping for an existing object" do
- {:ok, object} = Object.context_mapping("random context") |> Repo.insert
+ {:ok, object} = Object.context_mapping("random context") |> Repo.insert()
conversation_id = TwitterAPI.context_to_conversation_id("random context")
assert conversation_id == object.id
test "A user with an avatar object", %{user: user} do
image = "image"
- user = %{ user | avatar: %{ "url" => [%{"href" => image}] }}
+ user = %{user | avatar: %{"url" => [%{"href" => image}]}}
represented = UserView.render("show.json", %{user: user})
assert represented["profile_image_url"] == image
end
"name" => user.name,
"screen_name" => user.nickname,
"description" => HtmlSanitizeEx.strip_tags(user.bio),
- "created_at" => user.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"favourites_count" => 0,
"statuses_count" => 1,
"friends_count" => 1,
"name" => user.name,
"screen_name" => user.nickname,
"description" => HtmlSanitizeEx.strip_tags(user.bio),
- "created_at" => user.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"favourites_count" => 0,
"statuses_count" => 0,
"friends_count" => 0,
"name" => follower.name,
"screen_name" => follower.nickname,
"description" => HtmlSanitizeEx.strip_tags(follower.bio),
- "created_at" => follower.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => follower.inserted_at |> Utils.format_naive_asctime(),
"favourites_count" => 0,
"statuses_count" => 0,
"friends_count" => 1,
"name" => user.name,
"screen_name" => user.nickname,
"description" => HtmlSanitizeEx.strip_tags(user.bio),
- "created_at" => user.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"favourites_count" => 0,
"statuses_count" => 0,
"friends_count" => 0,
import Phoenix.View
test "renders 404.json" do
- assert render(Pleroma.Web.ErrorView, "404.json", []) ==
- %{errors: %{detail: "Page not found"}}
+ assert render(Pleroma.Web.ErrorView, "404.json", []) == %{errors: %{detail: "Page not found"}}
end
test "render 500.json" do
assert render(Pleroma.Web.ErrorView, "500.json", []) ==
- %{errors: %{detail: "Internal server error"}}
+ %{errors: %{detail: "Internal server error"}}
end
test "render any other" do
assert render(Pleroma.Web.ErrorView, "505.json", []) ==
- %{errors: %{detail: "Internal server error"}}
+ %{errors: %{detail: "Internal server error"}}
end
end
test "returns a link to the xml lrdd" do
host_info = WebFinger.host_meta()
- assert String.contains?(host_info, Pleroma.Web.base_url)
+ assert String.contains?(host_info, Pleroma.Web.base_url())
end
end
test "works for fqns" do
user = insert(:user)
- {:ok, result} = WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host}", "XML")
+ {:ok, result} =
+ WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "XML")
+
assert is_binary(result)
end
{:ok, data} = WebFinger.finger(user)
- assert data["magic_key"] == "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB"
+ assert data["magic_key"] ==
+ "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB"
+
assert data["topic"] == "https://social.heldscal.la/api/statuses/user_timeline/29191.atom"
assert data["subject"] == "acct:shp@social.heldscal.la"
assert data["salmon"] == "https://social.heldscal.la/main/salmon/user/29191"
{:ok, data} = WebFinger.finger(user)
- assert data["magic_key"] == "RSA.qfYaxztz7ZELrE4v5WpJrPM99SKI3iv9Y3Tw6nfLGk-4CRljNYqV8IYX2FXjeucC_DKhPNnlF6fXyASpcSmA_qupX9WC66eVhFhZ5OuyBOeLvJ1C4x7Hi7Di8MNBxY3VdQuQR0tTaS_YAZCwASKp7H6XEid3EJpGt0EQZoNzRd8=.AQAB"
+ assert data["magic_key"] ==
+ "RSA.qfYaxztz7ZELrE4v5WpJrPM99SKI3iv9Y3Tw6nfLGk-4CRljNYqV8IYX2FXjeucC_DKhPNnlF6fXyASpcSmA_qupX9WC66eVhFhZ5OuyBOeLvJ1C4x7Hi7Di8MNBxY3VdQuQR0tTaS_YAZCwASKp7H6XEid3EJpGt0EQZoNzRd8=.AQAB"
+
assert data["topic"] == "https://gnusocial.de/api/statuses/user_timeline/249296.atom"
assert data["subject"] == "acct:winterdienst@gnusocial.de"
assert data["salmon"] == "https://gnusocial.de/main/salmon/user/249296"
"hub.lease_seconds": "100"
}
- conn = conn
- |> post(path, data)
+ conn =
+ conn
+ |> post(path, data)
assert response(conn, 202) == "Accepted"
end
"hub.lease_seconds" => "100"
}
- conn = conn
- |> get("/push/subscriptions/#{websub.id}", params)
+ conn =
+ conn
+ |> get("/push/subscriptions/#{websub.id}", params)
websub = Repo.get(WebsubClientSubscription, websub.id)
assert response(conn, 200) == "some challenge"
assert websub.state == "accepted"
- assert_in_delta NaiveDateTime.diff(websub.valid_until, NaiveDateTime.utc_now), 100, 5
+ assert_in_delta NaiveDateTime.diff(websub.valid_until, NaiveDateTime.utc_now()), 100, 5
end
test "handles incoming feed updates", %{conn: conn} do
doc = "some stuff"
signature = Websub.sign(websub.secret, doc)
- conn = conn
- |> put_req_header("x-hub-signature", "sha1=" <> signature)
- |> put_req_header("content-type", "application/atom+xml")
- |> post("/push/subscriptions/#{websub.id}", doc)
+ conn =
+ conn
+ |> put_req_header("x-hub-signature", "sha1=" <> signature)
+ |> put_req_header("content-type", "application/atom+xml")
+ |> post("/push/subscriptions/#{websub.id}", doc)
assert response(conn, 200) == "OK"
doc = "some stuff"
signature = Websub.sign("wrong secret", doc)
- conn = conn
- |> put_req_header("x-hub-signature", "sha1=" <> signature)
- |> put_req_header("content-type", "application/atom+xml")
- |> post("/push/subscriptions/#{websub.id}", doc)
+ conn =
+ conn
+ |> put_req_header("x-hub-signature", "sha1=" <> signature)
+ |> put_req_header("content-type", "application/atom+xml")
+ |> post("/push/subscriptions/#{websub.id}", doc)
assert response(conn, 500) == "Error"
sub = insert(:websub_subscription)
topic = sub.topic
- getter = fn (_path, _headers, options) ->
+ getter = fn _path, _headers, options ->
%{
"hub.challenge": challenge,
"hub.lease_seconds": seconds,
assert String.to_integer(seconds) > 0
- {:ok, %HTTPoison.Response{
- status_code: 200,
- body: challenge
- }}
+ {:ok,
+ %HTTPoison.Response{
+ status_code: 200,
+ body: challenge
+ }}
end
{:ok, sub} = Websub.verify(sub, getter)
test "a verification of a request that doesn't return 200" do
sub = insert(:websub_subscription)
- getter = fn (_path, _headers, _options) ->
- {:ok, %HTTPoison.Response{
- status_code: 500,
- body: ""
- }}
+ getter = fn _path, _headers, _options ->
+ {:ok,
+ %HTTPoison.Response{
+ status_code: 500,
+ body: ""
+ }}
end
{:error, sub} = Websub.verify(sub, getter)
"hub.lease_seconds" => "100"
}
- {:ok, subscription } = Websub.incoming_subscription_request(user, data)
+ {:ok, subscription} = Websub.incoming_subscription_request(user, data)
assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
assert subscription.state == "requested"
assert subscription.secret == "a random secret"
test "an incoming subscription request for an existing subscription" do
user = insert(:user)
- sub = insert(:websub_subscription, state: "accepted", topic: Pleroma.Web.OStatus.feed_path(user))
+
+ sub =
+ insert(:websub_subscription, state: "accepted", topic: Pleroma.Web.OStatus.feed_path(user))
data = %{
"hub.callback" => sub.callback,
"hub.lease_seconds" => "100"
}
- {:ok, subscription } = Websub.incoming_subscription_request(user, data)
+ {:ok, subscription} = Websub.incoming_subscription_request(user, data)
assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
assert subscription.state == sub.state
assert subscription.secret == "a random secret"
end
def accepting_verifier(subscription) do
- {:ok, %{ subscription | state: "accepted" }}
+ {:ok, %{subscription | state: "accepted"}}
end
test "initiate a subscription for a given user and topic" do
subscriber = insert(:user)
- user = insert(:user, %{info: %{ "topic" => "some_topic", "hub" => "some_hub"}})
+ user = insert(:user, %{info: %{"topic" => "some_topic", "hub" => "some_hub"}})
{:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1)
assert websub.subscribers == [subscriber.ap_id]
test "discovers the hub and canonical url" do
topic = "https://mastodon.social/users/lambadalambda.atom"
- getter = fn(^topic) ->
+ getter = fn ^topic ->
doc = File.read!("test/fixtures/lambadalambda.atom")
{:ok, %{status_code: 200, body: doc}}
end
{:ok, discovered} = Websub.gather_feed_data(topic, getter)
+
expected = %{
"hub" => "https://mastodon.social/api/push",
"uri" => "https://mastodon.social/users/lambadalambda",
"name" => "Critical Value",
"host" => "mastodon.social",
"bio" => "a cool dude.",
- "avatar" => %{"type" => "Image", "url" => [%{"href" => "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244", "mediaType" => "image/gif", "type" => "Link"}]}
+ "avatar" => %{
+ "type" => "Image",
+ "url" => [
+ %{
+ "href" =>
+ "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244",
+ "mediaType" => "image/gif",
+ "type" => "Link"
+ }
+ ]
+ }
}
assert expected == discovered
topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom"
websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})
- poster = fn (^hub, {:form, data}, _headers) ->
+ poster = fn ^hub, {:form, data}, _headers ->
assert Keyword.get(data, :"hub.mode") == "subscribe"
- assert Keyword.get(data, :"hub.callback") == Helpers.websub_url(Pleroma.Web.Endpoint, :websub_subscription_confirmation, websub.id)
+
+ assert Keyword.get(data, :"hub.callback") ==
+ Helpers.websub_url(
+ Pleroma.Web.Endpoint,
+ :websub_subscription_confirmation,
+ websub.id
+ )
+
{:ok, %{status_code: 202}}
end
topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom"
websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})
- poster = fn (^hub, {:form, _data}, _headers) ->
+ poster = fn ^hub, {:form, _data}, _headers ->
{:ok, %{status_code: 202}}
end
assert websub.state == "rejected"
websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})
- poster = fn (^hub, {:form, _data}, _headers) ->
+
+ poster = fn ^hub, {:form, _data}, _headers ->
{:ok, %{status_code: 400}}
end
test "sign a text" do
signed = Websub.sign("secret", "text")
- assert signed == "B8392C23690CCF871F37EC270BE1582DEC57A503" |> String.downcase
+ assert signed == "B8392C23690CCF871F37EC270BE1582DEC57A503" |> String.downcase()
_signed = Websub.sign("secret", [["て"], ['す']])
end
describe "renewing subscriptions" do
test "it renews subscriptions that have less than a day of time left" do
day = 60 * 60 * 24
- now = NaiveDateTime.utc_now
- still_good = insert(:websub_client_subscription, %{valid_until: NaiveDateTime.add(now, 2 * day), topic: "http://example.org/still_good", state: "accepted"})
- needs_refresh = insert(:websub_client_subscription, %{valid_until: NaiveDateTime.add(now, day - 100), topic: "http://example.org/needs_refresh", state: "accepted"})
+ now = NaiveDateTime.utc_now()
+
+ still_good =
+ insert(:websub_client_subscription, %{
+ valid_until: NaiveDateTime.add(now, 2 * day),
+ topic: "http://example.org/still_good",
+ state: "accepted"
+ })
+
+ needs_refresh =
+ insert(:websub_client_subscription, %{
+ valid_until: NaiveDateTime.add(now, day - 100),
+ topic: "http://example.org/needs_refresh",
+ state: "accepted"
+ })
_refresh = Websub.refresh_subscriptions()
alias Pleroma.XmlBuilder
test "Build a basic xml string from a tuple" do
- data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" }
+ data = {:feed, %{xmlns: "http://www.w3.org/2005/Atom"}, "Some content"}
expected_xml = "<feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>"
end
test "returns a complete document" do
- data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" }
+ data = {:feed, %{xmlns: "http://www.w3.org/2005/Atom"}, "Some content"}
- expected_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>"
+ expected_xml =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>"
assert XmlBuilder.to_doc(data) == expected_xml
end
:feed,
[
{:guy, "brush"},
- {:lament, %{ configuration: "puzzle" }, "pinhead" }
+ {:lament, %{configuration: "puzzle"}, "pinhead"}
]
}
- expected_xml = ~s[<feed><guy>brush</guy><lament configuration="puzzle">pinhead</lament></feed>]
+ expected_xml =
+ ~s[<feed><guy>brush</guy><lament configuration="puzzle">pinhead</lament></feed>]
assert XmlBuilder.to_xml(data) == expected_xml
end
test "Uses self-closing tags when no content is giving" do
data = {
:link,
- %{ rel: "self" }
+ %{rel: "self"}
}
expected_xml = ~s[<link rel="self" />]