* Run `mix ecto.migrate` to run the database migrations. You will have to do this again after certain updates.
* You can check if your instance is configured correctly by running it with `mix phx.server` and checking the instance info endpoint at `/api/v1/instance`. If it shows your uri, name and email correctly, you are configured correctly. If it shows something like `localhost:4000`, your configuration is probably wrong, unless you are running a local development setup.
* The common and convenient way for adding HTTPS is by using Nginx as a reverse proxy. You can look at example Nginx configuration in `installation/pleroma.nginx`. If you need TLS/SSL certificates for HTTPS, you can look get some for free with letsencrypt: . The simplest way to obtain and install a certificate is to use [Certbot.](https://certbot.eff.org) Depending on your specific setup, certbot may be able to get a certificate and configure your web server automatically.
@@ -66,7 +68,7 @@ This is useful for running Pleroma inside Tor or I2P.
## Customization and contribution
-The [Pleroma Wiki](https://git.pleroma.social/pleroma/pleroma/wikis/home) offers manuals and guides on how to further customize your instance to your liking and how you can contribute to the project.
+The [Pleroma Documentation](https://docs-develop.pleroma.social/readme.html) offers manuals and guides on how to further customize your instance to your liking and how you can contribute to the project.
## Troubleshooting
diff --git a/config/config.exs b/config/config.exs
index 0df38d75a..dccf7b263 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -378,6 +378,8 @@
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
uid: System.get_env("LDAP_UID") || "cn"
+config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Sendmail
+
# 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"
diff --git a/docs/admin/backup.md b/docs/admin/backup.md
index b373996f5..2c70e7bf8 100644
--- a/docs/admin/backup.md
+++ b/docs/admin/backup.md
@@ -1,4 +1,6 @@
-# Backup your instance
+# Backup/Restore your instance
+
+## Backup
1. Stop the Pleroma service.
2. Go to the working directory of Pleroma (default is `/opt/pleroma`)
@@ -6,7 +8,7 @@
4. Copy `pleroma.pgdump`, `config/prod.secret.exs` and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too.
5. Restart the Pleroma service.
-## Restore your instance
+## Restore
1. Stop the Pleroma service.
2. Go to the working directory of Pleroma (default is `/opt/pleroma`)
diff --git a/docs/admin/updating.md b/docs/admin/updating.md
index 33ce1ab4f..84e6ef18d 100644
--- a/docs/admin/updating.md
+++ b/docs/admin/updating.md
@@ -1,9 +1,9 @@
# Updating your instance
-1. Stop the Pleroma service.
-2. Go to the working directory of Pleroma (default is `/opt/pleroma`)
-3. Run `git pull`. This pulls the latest changes from upstream.
-4. Run `mix deps.get`. This pulls in any new dependencies.
+1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
+2. Run `git pull`. This pulls the latest changes from upstream.
+3. Run `mix deps.get`. This pulls in any new dependencies.
+4. Stop the Pleroma service.
5. Run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
-6. Restart the Pleroma service.
+6. Start the Pleroma service.
[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
diff --git a/docs/api/differences_in_mastoapi_responses.md b/docs/api/differences_in_mastoapi_responses.md
index d993d1383..215f43155 100644
--- a/docs/api/differences_in_mastoapi_responses.md
+++ b/docs/api/differences_in_mastoapi_responses.md
@@ -44,3 +44,9 @@ Has these additional fields under the `pleroma` object:
Has these additional fields under the `pleroma` object:
- `is_seen`: true if the notification was read by the user
+
+## POST `/api/v1/statuses`
+
+Additional parameters can be added to the JSON body/Form data:
+
+- `preview`: boolean, if set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example.
diff --git a/docs/config.md b/docs/config.md
index 3624e295b..97a0e6ffa 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -193,6 +193,44 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
* `port`: Port to bind to
* `dstport`: Port advertised in urls (optional, defaults to `port`)
+## Pleroma.Web.Endpoint
+`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here
+* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here
+ - `ip` - a tuple consisting of 4 integers
+ - `port`
+* `url` - a list containing the configuration for generating urls, accepts
+ - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
+ - `scheme` - e.g `http`, `https`
+ - `port`
+ - `path`
+
+
+**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
+
+Example:
+```elixir
+config :pleroma, Pleroma.Web.Endpoint,
+ url: [host: "example.com", port: 2020, scheme: "https"],
+ http: [
+ # start copied from config.exs
+ dispatch: [
+ {:_,
+ [
+ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+ {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+ {Phoenix.Transports.WebSocket,
+ {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
+ {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+ ]}
+ # end copied from config.exs
+ ],
+ port: 8080,
+ ip: {127, 0, 0, 1}
+ ]
+```
+
+This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020`
+
## :activitypub
* ``accept_blocks``: Whether to accept incoming block activities from other instances
* ``unfollow_blocked``: Whether blocks result in people getting unfollowed
diff --git a/docs/config/howto_change_ip_and_port.md b/docs/config/howto_change_ip_and_port.md
deleted file mode 100644
index decddd35c..000000000
--- a/docs/config/howto_change_ip_and_port.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# How to change the port or IP Pleroma listens to
-To change the port or IP Pleroma listens to, head over to your generated config inside the Pleroma folder at config/prod.secret.exs and edit the following according to your needs.
-```
-config :pleroma, Pleroma.Web.Endpoint,
- [...]
- http: [ip: {127, 0, 0, 1}, port: 4000]
-```
diff --git a/docs/introduction.md b/docs/introduction.md
index 096a23277..4af0747fe 100644
--- a/docs/introduction.md
+++ b/docs/introduction.md
@@ -1,11 +1,11 @@
# Introduction to Pleroma
-**What is Pleroma?**
+## What is Pleroma?
Pleroma is a federated social networking platform, compatible with GNU social, Mastodon and other OStatus and ActivityPub implementations. It is free software licensed under the AGPLv3.
It actually consists of two components: a backend, named simply Pleroma, and a user-facing frontend, named Pleroma-FE. It also includes the Mastodon frontend, if that's your thing.
It's part of what we call the fediverse, a federated network of instances which speak common protocols and can communicate with each other.
One account on a instance is enough to talk to the entire fediverse!
-**How can I use it?**
+## How can I use it?
Pleroma instances are already widely deployed, a list can be found here:
http://distsn.org/pleroma-instances.html
@@ -14,14 +14,14 @@ If you don't feel like joining an existing instance, but instead prefer to deplo
Installation instructions can be found here:
[main Pleroma wiki](/)
-**I got an account, now what?**
+## I got an account, now what?
Great! Now you can explore the fediverse!
- Open the login page for your Pleroma instance (for ex. https://pleroma.soykaf.com) and login with your username and password.
(If you don't have one yet, click on Register) :slightly_smiling_face:
At this point you will have two columns in front of you.
-***left column***
+### Left column
- first block: here you can see your avatar, your nickname a bio, and statistics (Statuses, Following, Followers).
Under that you have a text form which allows you to post new statuses. The icon on the left is for uploading media files and attach them to your post. The number under the text form is a character counter, every instance can have a different character limit (the default is 5000).
If you want to mention someone, type @ + name of the person. A drop-down menu will help you in finding the right person. :slight_smile:
@@ -37,7 +37,7 @@ To post your status, simply press Submit.
- fourth block: This is the Notifications block, here you will get notified whenever somebody mentions you, follows you, repeats or favorites one of your statuses.
-***right column***
+### Right column
This is where the interesting stuff happens! :slight_smile:
Depending on the timeline you will see different statuses, but each status has a standard structure:
- Icon + name + link to profile. An optional left-arrow if it's a reply to another status (hovering will reveal the replied-to status).
@@ -46,7 +46,7 @@ Depending on the timeline you will see different statuses, but each status has a
- The text of the status, including mentions. If you click on a mention, it will automatically open the profile page of that person.
- Four buttons (left to right): Reply, Repeat, Favorite, Delete.
-**Mastodon interface**
+## Mastodon interface
If the Pleroma interface isn't your thing, or you're just trying something new but you want to keep using the familiar Mastodon interface, we got that too! :smile:
Just add a "/web" after your instance url (for ex. https://pleroma.soycaf.com/web) and you'll end on the Mastodon web interface, but with a Pleroma backend! MAGIC! :fireworks:
For more information on the Mastodon interface, please look here:
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
index 1ba452275..8f8d86a11 100644
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -81,6 +81,14 @@ def run(["gen" | rest]) do
email = Common.get_option(options, :admin_email, "What is your admin email address?")
+ indexable =
+ Common.get_option(
+ options,
+ :indexable,
+ "Do you want search engines to index your site? (y/n)",
+ "y"
+ ) === "y"
+
dbhost =
Common.get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
@@ -142,6 +150,8 @@ def run(["gen" | rest]) do
Mix.shell().info("Writing #{psql_path}.")
File.write(psql_path, result_psql)
+ write_robots_txt(indexable)
+
Mix.shell().info(
"\n" <>
"""
@@ -163,4 +173,28 @@ def run(["gen" | rest]) do
)
end
end
+
+ defp write_robots_txt(indexable) do
+ robots_txt =
+ EEx.eval_file(
+ Path.expand("robots_txt.eex", __DIR__),
+ indexable: indexable
+ )
+
+ static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
+
+ unless File.exists?(static_dir) do
+ File.mkdir_p!(static_dir)
+ end
+
+ robots_txt_path = Path.join(static_dir, "robots.txt")
+
+ if File.exists?(robots_txt_path) do
+ File.cp!(robots_txt_path, "#{robots_txt_path}.bak")
+ Mix.shell().info("Backing up existing robots.txt to #{robots_txt_path}.bak")
+ end
+
+ File.write(robots_txt_path, robots_txt)
+ Mix.shell().info("Writing #{robots_txt_path}.")
+ end
end
diff --git a/lib/mix/tasks/pleroma/robots_txt.eex b/lib/mix/tasks/pleroma/robots_txt.eex
new file mode 100644
index 000000000..1af3c47ee
--- /dev/null
+++ b/lib/mix/tasks/pleroma/robots_txt.eex
@@ -0,0 +1,2 @@
+User-Agent: *
+Disallow: <%= if indexable, do: "", else: "/" %>
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index f6cca0d06..0d0bea8c0 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -6,7 +6,6 @@ defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Ecto.Changeset
alias Mix.Tasks.Pleroma.Common
- alias Pleroma.Repo
alias Pleroma.User
@shortdoc "Manages Pleroma users"
@@ -23,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.User do
- `--password PASSWORD` - the user's password
- `--moderator`/`--no-moderator` - whether the user is a moderator
- `--admin`/`--no-admin` - whether the user is an admin
- - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
+ - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
## Generate an invite link.
@@ -33,6 +32,10 @@ defmodule Mix.Tasks.Pleroma.User do
mix pleroma.user rm NICKNAME
+ ## Delete the user's activities.
+
+ mix pleroma.user delete_activities NICKNAME
+
## Deactivate or activate the user's account.
mix pleroma.user toggle_activated NICKNAME
@@ -202,7 +205,7 @@ def run(["unsubscribe", nickname]) do
{:ok, friends} = User.get_friends(user)
Enum.each(friends, fn friend ->
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
User.unfollow(user, friend)
@@ -210,7 +213,7 @@ def run(["unsubscribe", nickname]) do
:timer.sleep(500)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
if Enum.empty?(user.following) do
Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
@@ -304,6 +307,18 @@ def run(["invite"]) do
end
end
+ def run(["delete_activities", nickname]) do
+ Common.start_pleroma()
+
+ with %User{local: true} = user <- User.get_by_nickname(nickname) do
+ User.delete_user_activities(user)
+ Mix.shell().info("User #{nickname} statuses deleted.")
+ else
+ _ ->
+ Mix.shell().error("No local user #{nickname}")
+ end
+ end
+
defp set_moderator(user, value) do
info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value})
diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
index 772c239a1..7afbc8751 100644
--- a/lib/pleroma/PasswordResetToken.ex
+++ b/lib/pleroma/PasswordResetToken.ex
@@ -39,7 +39,7 @@ def used_changeset(struct) do
def reset_password(token, data) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id),
+ %User{} = user <- User.get_by_id(token.user_id),
{:ok, _user} <- User.reset_password(user, data),
{:ok, token} <- Repo.update(used_changeset(token)) do
{:ok, token}
diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex
index 4259d5718..58ab3650d 100644
--- a/lib/pleroma/flake_id.ex
+++ b/lib/pleroma/flake_id.ex
@@ -46,7 +46,7 @@ def from_string(<<_::integer-size(128)>> = flake), do: flake
def from_string(string) when is_binary(string) and byte_size(string) < 18 do
case Integer.parse(string) do
- {id, _} -> <<0::integer-size(64), id::integer-size(64)>>
+ {id, ""} -> <<0::integer-size(64), id::integer-size(64)>>
_ -> nil
end
end
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
index 3b9629d77..6a56a6f67 100644
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -38,7 +38,6 @@ def init([ip, port]) do
defmodule Pleroma.Gopher.Server.ProtocolHandler do
alias Pleroma.Activity
alias Pleroma.HTML
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
@@ -111,7 +110,7 @@ def response("/main/all") do
end
def response("/notices/" <> id) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.is_public?(activity) do
activities =
ActivityPub.fetch_activities_for_context(activity.data["context"])
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 5b152d926..1e48749a8 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -28,9 +28,13 @@ def filter_tags(html, scrubber), do: Scrubber.scrub(html, scrubber)
def filter_tags(html), do: filter_tags(html, nil)
def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags)
+ # TODO: rename object to activity because that's what it is really working with
def get_cached_scrubbed_html_for_object(content, scrubbers, object, module) do
key = "#{module}#{generate_scrubber_signature(scrubbers)}|#{object.id}"
- Cachex.fetch!(:scrubber_cache, key, fn _key -> ensure_scrubbed_html(content, scrubbers) end)
+
+ Cachex.fetch!(:scrubber_cache, key, fn _key ->
+ ensure_scrubbed_html(content, scrubbers, object.data["object"]["fake"] || false)
+ end)
end
def get_cached_stripped_html_for_object(content, object, module) do
@@ -44,11 +48,20 @@ def get_cached_stripped_html_for_object(content, object, module) do
def ensure_scrubbed_html(
content,
- scrubbers
+ scrubbers,
+ false = _fake
) do
{:commit, filter_tags(content, scrubbers)}
end
+ def ensure_scrubbed_html(
+ content,
+ scrubbers,
+ true = _fake
+ ) do
+ {:ignore, filter_tags(content, scrubbers)}
+ end
+
defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do
generate_scrubber_signature([scrubber])
end
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
index 55c4cf6df..110be8355 100644
--- a/lib/pleroma/list.ex
+++ b/lib/pleroma/list.ex
@@ -80,7 +80,7 @@ def get_lists_from_activity(%Activity{actor: ap_id}) do
# Get lists to which the account belongs.
def get_lists_account_belongs(%User{} = owner, account_id) do
- user = Repo.get(User, account_id)
+ user = User.get_by_id(account_id)
query =
from(
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 8a670645d..013d62157 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -44,6 +44,11 @@ def get_by_ap_id(ap_id) do
# Use this whenever possible, especially when walking graphs in an O(N) loop!
def normalize(%Activity{object: %Object{} = object}), do: object
+ # A hack for fake activities
+ def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}) do
+ %Object{id: "pleroma:fake_object_id", data: data}
+ end
+
# Catch and log Object.normalize() calls where the Activity's child object is not
# preloaded.
def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}) do
diff --git a/lib/pleroma/plugs/user_fetcher_plug.ex b/lib/pleroma/plugs/user_fetcher_plug.ex
index 5a77f6833..4089aa958 100644
--- a/lib/pleroma/plugs/user_fetcher_plug.ex
+++ b/lib/pleroma/plugs/user_fetcher_plug.ex
@@ -3,9 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Plugs.UserFetcherPlug do
- alias Pleroma.Repo
alias Pleroma.User
-
import Plug.Conn
def init(options) do
@@ -14,26 +12,10 @@ def init(options) do
def call(conn, _options) do
with %{auth_credentials: %{username: username}} <- conn.assigns,
- {:ok, %User{} = user} <- user_fetcher(username) do
- conn
- |> assign(:auth_user, user)
+ %User{} = user <- User.get_by_nickname_or_email(username) do
+ assign(conn, :auth_user, user)
else
_ -> conn
end
end
-
- defp user_fetcher(username_or_email) do
- {
- :ok,
- cond do
- # First, try logging in as if it was a name
- user = Repo.get_by(User, %{nickname: username_or_email}) ->
- user
-
- # If we get nil, we try using it as an email
- user = Repo.get_by(User, %{email: username_or_email}) ->
- user
- end
- }
- end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 728b00a56..5012aef77 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1088,28 +1088,27 @@ def delete(%User{} = user) do
# Remove all relationships
{:ok, followers} = User.get_followers(user)
- followers
- |> Enum.each(fn follower -> User.unfollow(follower, user) end)
+ Enum.each(followers, 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(friends, fn followed -> User.unfollow(user, followed) end)
- query =
- from(a in Activity, where: a.actor == ^user.ap_id)
- |> Activity.with_preloaded_object()
+ delete_user_activities(user)
+ end
- Repo.all(query)
- |> Enum.each(fn activity ->
- case activity.data["type"] do
- "Create" ->
- ActivityPub.delete(Object.normalize(activity))
+ def delete_user_activities(%User{ap_id: ap_id} = user) do
+ Activity
+ |> where(actor: ^ap_id)
+ |> Activity.with_preloaded_object()
+ |> Repo.all()
+ |> Enum.each(fn
+ %{data: %{"type" => "Create"}} = activity ->
+ activity |> Object.normalize() |> ActivityPub.delete()
- # TODO: Do something with likes, follows, repeats.
- _ ->
- "Doing nothing"
- end
+ # TODO: Do something with likes, follows, repeats.
+ _ ->
+ "Doing nothing"
end)
{:ok, user}
@@ -1231,8 +1230,8 @@ def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname)
# this is because we have synchronous follow APIs and need to simulate them
# with an async handshake
def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
- with %User{} = a <- Repo.get(User, a.id),
- %User{} = b <- Repo.get(User, b.id) do
+ with %User{} = a <- User.get_by_id(a.id),
+ %User{} = b <- User.get_by_id(b.id) do
{:ok, a, b}
else
_e ->
@@ -1242,8 +1241,8 @@ def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
def wait_and_refresh(timeout, %User{} = a, %User{} = b) do
with :ok <- :timer.sleep(timeout),
- %User{} = a <- Repo.get(User, a.id),
- %User{} = b <- Repo.get(User, b.id) do
+ %User{} = a <- User.get_by_id(a.id),
+ %User{} = b <- User.get_by_id(b.id) do
{:ok, a, b}
else
_e ->
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 6e1ed7ec9..f217e7bac 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -113,15 +113,15 @@ def decrease_replies_count_if_reply(%Object{
def decrease_replies_count_if_reply(_object), do: :noop
- def insert(map, local \\ true) when is_map(map) do
+ def insert(map, local \\ true, fake \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
- map <- lazy_put_activity_defaults(map),
+ map <- lazy_put_activity_defaults(map, fake),
:ok <- check_actor_is_active(map["actor"]),
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
+ {recipients, _, _} = get_recipients(map),
+ {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
{:ok, object} <- insert_full_object(map) do
- {recipients, _, _} = get_recipients(map)
-
{:ok, activity} =
Repo.insert(%Activity{
data: map,
@@ -146,8 +146,23 @@ def insert(map, local \\ true) when is_map(map) do
stream_out(activity)
{:ok, activity}
else
- %Activity{} = activity -> {:ok, activity}
- error -> {:error, error}
+ %Activity{} = activity ->
+ {:ok, activity}
+
+ {:fake, true, map, recipients} ->
+ activity = %Activity{
+ data: map,
+ local: local,
+ actor: map["actor"],
+ recipients: recipients,
+ id: "pleroma:fakeid"
+ }
+
+ Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ {:ok, activity}
+
+ error ->
+ {:error, error}
end
end
@@ -190,7 +205,7 @@ def stream_out(activity) do
end
end
- def create(%{to: to, actor: actor, context: context, object: object} = params) do
+ def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do
additional = params[:additional] || %{}
# only accept false as false value
local = !(params[:local] == false)
@@ -201,13 +216,17 @@ def create(%{to: to, actor: actor, context: context, object: object} = params) d
%{to: to, actor: actor, published: published, context: context, object: object},
additional
),
- {:ok, activity} <- insert(create_data, local),
+ {:ok, activity} <- insert(create_data, local, fake),
+ {:fake, false, activity} <- {:fake, fake, activity},
_ <- increase_replies_count_if_reply(create_data),
# Changing note count prior to enqueuing federation task in order to avoid
# race conditions on updating user.info
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
+ else
+ {:fake, true, activity} ->
+ {:ok, activity}
end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 2e9ffe41c..32545937e 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -175,18 +175,26 @@ def maybe_federate(_), do: :ok
Adds an id and a published data if they aren't there,
also adds it to an included object
"""
- def lazy_put_activity_defaults(map) do
- %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
-
+ def lazy_put_activity_defaults(map, fake \\ false) do
map =
- map
- |> Map.put_new_lazy("id", &generate_activity_id/0)
- |> Map.put_new_lazy("published", &make_date/0)
- |> Map.put_new("context", context)
- |> Map.put_new("context_id", context_id)
+ unless fake do
+ %{data: %{"id" => context}, id: context_id} = create_context(map["context"])
+
+ map
+ |> Map.put_new_lazy("id", &generate_activity_id/0)
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("context", context)
+ |> Map.put_new("context_id", context_id)
+ else
+ map
+ |> Map.put_new("id", "pleroma:fakeid")
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("context", "pleroma:fakecontext")
+ |> Map.put_new("context_id", -1)
+ end
if is_map(map["object"]) do
- object = lazy_put_object_defaults(map["object"], map)
+ object = lazy_put_object_defaults(map["object"], map, fake)
%{map | "object" => object}
else
map
@@ -196,7 +204,18 @@ def lazy_put_activity_defaults(map) do
@doc """
Adds an id and published date if they aren't there.
"""
- def lazy_put_object_defaults(map, activity \\ %{}) do
+ def lazy_put_object_defaults(map, activity \\ %{}, fake)
+
+ def lazy_put_object_defaults(map, activity, true = _fake) do
+ map
+ |> Map.put_new_lazy("published", &make_date/0)
+ |> Map.put_new("id", "pleroma:fake_object_id")
+ |> Map.put_new("context", activity["context"])
+ |> Map.put_new("fake", true)
+ |> Map.put_new("context_id", activity["context_id"])
+ end
+
+ def lazy_put_object_defaults(map, activity, _fake) do
map
|> Map.put_new_lazy("id", &generate_object_id/0)
|> Map.put_new_lazy("published", &make_date/0)
@@ -354,7 +373,7 @@ def update_follow_state(
[state, actor, object]
)
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
{:ok, activity}
rescue
e ->
@@ -404,13 +423,15 @@ def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
activity.data
),
where: activity.actor == ^follower_id,
+ # this is to use the index
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
activity.data,
- ^%{object: followed_id}
+ activity.data,
+ ^followed_id
),
- order_by: [desc: :id],
+ order_by: [fragment("? desc nulls last", activity.id)],
limit: 1
)
@@ -567,13 +588,15 @@ def fetch_latest_block(%User{ap_id: blocker_id}, %User{ap_id: blocked_id}) do
activity.data
),
where: activity.actor == ^blocker_id,
+ # this is to use the index
where:
fragment(
- "? @> ?",
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
activity.data,
- ^%{object: blocked_id}
+ activity.data,
+ ^blocked_id
),
- order_by: [desc: :id],
+ order_by: [fragment("? desc nulls last", activity.id)],
limit: 1
)
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 3a700fa3b..6503979a1 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.UserSocket do
def connect(%{"token" => token}, socket) do
with true <- Pleroma.Config.get([:chat, :enabled]),
{:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
- %User{} = user <- Pleroma.Repo.get(User, user_id) do
+ %User{} = user <- Pleroma.User.get_by_id(user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else
_e -> :error
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 25b990677..745d1839b 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -172,13 +172,16 @@ def post(user, %{"status" => status} = data) do
end)
) do
res =
- ActivityPub.create(%{
- to: to,
- actor: user,
- context: context,
- object: object,
- additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
- })
+ ActivityPub.create(
+ %{
+ to: to,
+ actor: user,
+ context: context,
+ object: object,
+ additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
+ },
+ Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
+ )
res
end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index f596f703b..9cd8b3758 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -15,6 +15,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
+ require Logger
+
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
activity =
@@ -31,7 +33,7 @@ def get_by_id_or_ap_id(id) do
def get_replied_to_activity(""), do: nil
def get_replied_to_activity(id) when not is_nil(id) do
- Repo.get(Activity, id)
+ Activity.get_by_id(id)
end
def get_replied_to_activity(_), do: nil
@@ -240,15 +242,21 @@ def format_asctime(date) do
Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y")
end
- def date_to_asctime(date) do
- with {:ok, date, _offset} <- date |> DateTime.from_iso8601() do
+ def date_to_asctime(date) when is_binary(date) do
+ with {:ok, date, _offset} <- DateTime.from_iso8601(date) do
format_asctime(date)
else
_e ->
+ Logger.warn("Date #{date} in wrong format, must be ISO 8601")
""
end
end
+ def date_to_asctime(date) do
+ Logger.warn("Date #{date} in wrong format, must be ISO 8601")
+ ""
+ end
+
def to_masto_date(%NaiveDateTime{} = date) do
date
|> NaiveDateTime.to_iso8601()
@@ -275,7 +283,7 @@ defp shortname(name) do
end
def confirm_current_password(user, password) do
- with %User{local: true} = db_user <- Repo.get(User, user.id),
+ with %User{local: true} = db_user <- User.get_by_id(user.id),
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
{:ok, db_user}
else
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index 4d6192db0..181483664 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
+ # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+ @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
+ def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
+ def truthy_param?(value), do: value not in @falsy_param_values
+
def oauth_scopes(params, default) do
# Note: `scopes` is used by Mastodon — supporting it but sticking to
# OAuth's standard `scope` wherever we control it
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index eee4e7678..89fd7629a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -285,7 +285,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do
end
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- Repo.get(User, params["id"]) do
+ with %User{} = user <- User.get_by_id(params["id"]) do
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
@@ -319,7 +319,7 @@ def dm_timeline(%{assigns: %{user: user}} = conn, params) do
end
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(StatusView)
@@ -328,7 +328,7 @@ def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
activities <-
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
"blocking_user" => user,
@@ -460,7 +460,7 @@ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
end
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
@@ -471,7 +471,7 @@ def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
@@ -593,7 +593,7 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
end
def favourited_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^likes)
users = Repo.all(q)
@@ -606,7 +606,7 @@ def favourited_by(conn, %{"id" => id}) do
end
def reblogged_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^announces)
users = Repo.all(q)
@@ -657,7 +657,7 @@ def hashtag_timeline(%{assigns: %{user: user}} = conn, params) do
end
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- Repo.get(User, id),
+ with %User{} = user <- User.get_by_id(id),
followers <- MastodonAPI.get_followers(user, params) do
followers =
cond do
@@ -674,7 +674,7 @@ def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
end
def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
- with %User{} = user <- Repo.get(User, id),
+ with %User{} = user <- User.get_by_id(id),
followers <- MastodonAPI.get_friends(user, params) do
followers =
cond do
@@ -699,7 +699,7 @@ def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
end
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
+ with %User{} = follower <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -713,7 +713,7 @@ def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}
end
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
+ with %User{} = follower <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
@@ -727,7 +727,7 @@ def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) d
end
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
+ with %User{} = followed <- User.get_by_id(id),
false <- User.following?(follower, followed),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
@@ -755,7 +755,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
end
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
- with %User{} = followed <- Repo.get_by(User, nickname: uri),
+ with %User{} = followed <- User.get_by_nickname(uri),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
@@ -769,7 +769,7 @@ def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
end
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
+ with %User{} = followed <- User.get_by_id(id),
{:ok, follower} <- CommonAPI.unfollow(follower, followed) do
conn
|> put_view(AccountView)
@@ -778,7 +778,7 @@ def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
end
def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.mute(muter, muted) do
conn
|> put_view(AccountView)
@@ -792,7 +792,7 @@ def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
end
def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.unmute(muter, muted) do
conn
|> put_view(AccountView)
@@ -813,7 +813,7 @@ def mutes(%{assigns: %{user: user}} = conn, _) do
end
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.block(blocker, blocked),
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
conn
@@ -828,7 +828,7 @@ def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
end
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.unblock(blocker, blocked),
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
conn
@@ -966,7 +966,7 @@ def favourites(%{assigns: %{user: user}} = conn, params) do
end
def bookmarks(%{assigns: %{user: user}} = conn, _) do
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
activities =
user.bookmarks
@@ -1023,7 +1023,7 @@ def add_to_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_ids" =>
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(User, account_id) do
+ %User{} = followed <- User.get_by_id(account_id) do
Pleroma.List.follow(list, followed)
end
end)
@@ -1035,7 +1035,7 @@ def remove_from_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_id
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(Pleroma.User, account_id) do
+ %User{} = followed <- Pleroma.User.get_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
@@ -1121,7 +1121,8 @@ def index(%{assigns: %{user: user}} = conn, _params) do
auto_play_gif: false,
display_sensitive_media: false,
reduce_motion: false,
- max_toot_chars: limit
+ max_toot_chars: limit,
+ mascot: "/images/pleroma-fox-tan-smol.png"
},
rights: %{
delete_others_notice: present?(user.info.is_moderator),
@@ -1249,16 +1250,22 @@ defp get_user_flavour(_) do
"glitch"
end
- def login(conn, %{"code" => code}) do
+ def login(%{assigns: %{user: %User{}}} = conn, _params) do
+ redirect(conn, to: local_mastodon_root_path(conn))
+ end
+
+ @doc "Local Mastodon FE login init action"
+ def login(conn, %{"code" => auth_token}) do
with {:ok, app} <- get_or_make_app(),
- %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id),
+ %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
{:ok, token} <- Token.exchange_token(app, auth) do
conn
|> put_session(:oauth_token, token.token)
- |> redirect(to: "/web/getting-started")
+ |> redirect(to: local_mastodon_root_path(conn))
end
end
+ @doc "Local Mastodon FE callback action"
def login(conn, _) do
with {:ok, app} <- get_or_make_app() do
path =
@@ -1276,6 +1283,8 @@ def login(conn, _) do
end
end
+ defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"])
+
defp get_or_make_app do
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
scopes = ["read", "write", "follow", "push"]
@@ -1312,7 +1321,7 @@ def logout(conn, _) do
def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Logger.debug("Unimplemented, returning unmodified relationship")
- with %User{} = target <- Repo.get(User, id) do
+ with %User{} = target <- User.get_by_id(id) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: target})
@@ -1454,7 +1463,7 @@ def suggestions(%{assigns: %{user: user}} = conn, _) do
end
def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
- with %Activity{} = activity <- Repo.get(Activity, status_id),
+ with %Activity{} = activity <- Activity.get_by_id(status_id),
true <- Visibility.visible_for_user?(activity, user) do
data =
StatusView.render(
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 9b262f461..1b3721e2b 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -90,7 +90,7 @@ defp allow_request(stream, nil) when stream in @anonymous_streams do
# Authenticated streams.
defp allow_request(stream, {"access_token", access_token}) when stream in @streams do
with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
- user = %User{} <- Repo.get(User, user_id) do
+ user = %User{} <- User.get_by_id(user_id) do
{:ok, user}
else
_ -> {:error, 403}
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index ebb3dd253..26d53df1a 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.Auth.Authenticator
+ alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
@@ -19,7 +20,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do
action_fallback(Pleroma.Web.OAuth.FallbackController)
- def authorize(conn, params) do
+ def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
+ if ControllerHelper.truthy_param?(params["force_login"]) do
+ do_authorize(conn, params)
+ else
+ redirect_uri =
+ if is_binary(params["redirect_uri"]) do
+ params["redirect_uri"]
+ else
+ app = Repo.preload(token, :app).app
+
+ app.redirect_uris
+ |> String.split()
+ |> Enum.at(0)
+ end
+
+ redirect(conn, external: redirect_uri(conn, redirect_uri))
+ end
+ end
+
+ def authorize(conn, params), do: do_authorize(conn, params)
+
+ defp do_authorize(conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
@@ -51,13 +73,7 @@ def create_authorization(conn, %{
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
- redirect_uri =
- if redirect_uri == "." do
- # Special case: Local MastodonFE
- mastodon_api_url(conn, :login)
- else
- redirect_uri
- end
+ redirect_uri = redirect_uri(conn, redirect_uri)
cond do
redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
@@ -108,7 +124,7 @@ def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do
fixed_token = fix_padding(params["code"]),
%Authorization{} = auth <-
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
- %User{} = user <- Repo.get(User, auth.user_id),
+ %User{} = user <- User.get_by_id(auth.user_id),
{:ok, token} <- Token.exchange_token(app, auth),
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
response = %{
@@ -221,4 +237,9 @@ defp get_app_from_request(conn, params) do
nil
end
end
+
+ # Special case: Local MastodonFE
+ defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
+
+ defp redirect_uri(_conn, redirect_uri), do: redirect_uri
end
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index a8b06db36..2b5ad9b94 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
- create_token(app, Repo.get(User, auth.user_id), auth.scopes)
+ create_token(app, User.get_by_id(auth.user_id), auth.scopes)
end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 9ccb4e535..605a327fc 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
+ pipeline :oauth do
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ end
+
pipeline :api do
plug(:accepts, ["json"])
plug(:fetch_session)
@@ -105,10 +110,6 @@ defmodule Pleroma.Web.Router do
plug(:accepts, ["json", "xml"])
end
- pipeline :oauth do
- plug(:accepts, ["html", "json"])
- end
-
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
end
@@ -200,7 +201,11 @@ defmodule Pleroma.Web.Router do
end
scope "/oauth", Pleroma.Web.OAuth do
- get("/authorize", OAuthController, :authorize)
+ scope [] do
+ pipe_through(:oauth)
+ get("/authorize", OAuthController, :authorize)
+ end
+
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
@@ -218,6 +223,7 @@ defmodule Pleroma.Web.Router do
get("/accounts/search", MastodonAPIController, :account_search)
get("/accounts/:id/lists", MastodonAPIController, :account_lists)
+ get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
get("/follow_requests", MastodonAPIController, :follow_requests)
get("/blocks", MastodonAPIController, :blocks)
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 592749b42..a82109f92 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.Streamer do
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
@@ -82,7 +81,7 @@ def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do
_ ->
Pleroma.List.get_lists_from_activity(item)
|> Enum.filter(fn list ->
- owner = Repo.get(User, list.user_id)
+ owner = User.get_by_id(list.user_id)
Visibility.visible_for_user?(item, owner)
end)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index faa733fec..3cdd7a2f2 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
require Logger
alias Comeonin.Pbkdf2
+ alias Pleroma.Activity
alias Pleroma.Emoji
alias Pleroma.Notification
alias Pleroma.PasswordResetToken
@@ -21,7 +22,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
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
+ %User{} = user <- User.get_by_id(token.user_id) do
render(conn, "password_reset.html", %{
token: token,
user: user
@@ -73,36 +74,52 @@ def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profil
end
def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
- {err, followee} = OStatus.find_or_make_user(acct)
- avatar = User.avatar_url(followee)
- name = followee.nickname
- id = followee.id
-
- if !!user do
- conn
- |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
+ if is_status?(acct) do
+ {:ok, object} = ActivityPub.fetch_object_from_id(acct)
+ %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
+ redirect(conn, to: "/notice/#{activity_id}")
else
- conn
- |> render("follow_login.html", %{
- error: false,
- acct: acct,
- avatar: avatar,
- name: name,
- id: id
- })
+ {err, followee} = OStatus.find_or_make_user(acct)
+ avatar = User.avatar_url(followee)
+ name = followee.nickname
+ id = followee.id
+
+ if !!user do
+ conn
+ |> 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
+ })
+ end
+ end
+ end
+
+ defp is_status?(acct) do
+ case ActivityPub.fetch_and_contain_remote_object_from_id(acct) do
+ {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
+ true
+
+ _ ->
+ false
end
end
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
- followee = Repo.get(User, id)
+ followee = User.get_by_id(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 <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -124,7 +141,7 @@ def do_remote_follow(conn, %{
end
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with %User{} = followee <- Repo.get(User, id),
+ with %User{} = followee <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 9978c7f64..9b081a316 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -20,7 +20,7 @@ def create_status(%User{} = user, %{"status" => _} = data) do
end
def delete(%User{} = user, id) do
- with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id),
+ with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id),
{:ok, activity} <- CommonAPI.delete(id, user) do
{:ok, activity}
end
@@ -227,12 +227,9 @@ def get_user(user \\ nil, params) do
end
%{"screen_name" => nickname} ->
- case target = Repo.get_by(User, nickname: nickname) do
- nil ->
- {:error, "No user with such screen_name"}
-
- _ ->
- {:ok, target}
+ case User.get_by_nickname(nickname) do
+ nil -> {:error, "No user with such screen_name"}
+ target -> {:ok, target}
end
_ ->
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 62cce18dc..a7ec9949c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -270,7 +270,7 @@ def unfollow(%{assigns: %{user: user}} = conn, params) do
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(ActivityView)
@@ -342,7 +342,7 @@ def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
end
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
+ activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
if activity.data["type"] == "Create" do
activity
@@ -434,7 +434,7 @@ def password_reset(conn, params) do
end
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
- with %User{} = user <- Repo.get(User, uid),
+ with %User{} = user <- User.get_by_id(uid),
true <- user.local,
true <- user.info.confirmation_pending,
true <- user.info.confirmation_token == token,
@@ -587,7 +587,7 @@ def friend_requests(conn, params) do
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
+ %User{} = follower <- User.get_by_id(uid),
{:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(UserView)
@@ -599,7 +599,7 @@ def approve_friend_request(conn, %{"user_id" => uid} = _params) do
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
+ %User{} = follower <- User.get_by_id(uid),
{:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(UserView)
diff --git a/mix.exs b/mix.exs
index 333f21a91..88da6332a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -93,7 +93,7 @@ defp deps do
{:timex, "~> 3.5"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
- ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"},
+ ref: "479dd343f4e563ff91215c8275f3b5c67e032850"},
{:pleroma_job_queue, "~> 0.2.0"}
]
end
diff --git a/mix.lock b/mix.lock
index f401258e9..9c454446a 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,5 +1,5 @@
%{
- "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd", [ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"]},
+ "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "479dd343f4e563ff91215c8275f3b5c67e032850", [ref: "479dd343f4e563ff91215c8275f3b5c67e032850"]},
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"},
"cachex": {:hex, :cachex, "3.0.2", "1351caa4e26e29f7d7ec1d29b53d6013f0447630bbf382b4fb5d5bad0209f203", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"},
diff --git a/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs b/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs
new file mode 100644
index 000000000..ebcd29389
--- /dev/null
+++ b/priv/repo/migrations/20190403131720_add_oauth_token_indexes.exs
@@ -0,0 +1,9 @@
+defmodule Pleroma.Repo.Migrations.AddOauthTokenIndexes do
+ use Ecto.Migration
+
+ def change do
+ create(unique_index(:oauth_tokens, [:token]))
+ create(index(:oauth_tokens, [:app_id]))
+ create(index(:oauth_tokens, [:user_id]))
+ end
+end
diff --git a/priv/static/images/pleroma-fox-tan-smol.png b/priv/static/images/pleroma-fox-tan-smol.png
new file mode 100644
index 000000000..e944d0e2a
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan-smol.png differ
diff --git a/priv/static/images/pleroma-fox-tan.png b/priv/static/images/pleroma-fox-tan.png
new file mode 100644
index 000000000..da0022ff2
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan.png differ
diff --git a/priv/static/images/pleroma-tan.png b/priv/static/images/pleroma-tan.png
new file mode 100644
index 000000000..6c12c8e46
Binary files /dev/null and b/priv/static/images/pleroma-tan.png differ
diff --git a/test/fixtures/httpoison_mock/emelie.atom b/test/fixtures/httpoison_mock/emelie.atom
new file mode 100644
index 000000000..ddaa1c6ca
--- /dev/null
+++ b/test/fixtures/httpoison_mock/emelie.atom
@@ -0,0 +1,306 @@
+
+
+ https://mastodon.social/users/emelie.atom
+ emelie 🎨
+ 23 / #Sweden / #Artist / #Equestrian / #GameDev
+
+If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
+ 2019-02-04T20:22:19Z
+ https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png
+
+ https://mastodon.social/users/emelie
+ http://activitystrea.ms/schema/1.0/person
+ https://mastodon.social/users/emelie
+ emelie
+ emelie@mastodon.social
+ <p>23 / <a href="https://mastodon.social/tags/sweden" class="mention hashtag" rel="tag">#<span>Sweden</span></a> / <a href="https://mastodon.social/tags/artist" class="mention hashtag" rel="tag">#<span>Artist</span></a> / <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>Equestrian</span></a> / <a href="https://mastodon.social/tags/gamedev" class="mention hashtag" rel="tag">#<span>GameDev</span></a></p><p>If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</p>
+
+
+
+ emelie
+ emelie 🎨
+ 23 / #Sweden / #Artist / #Equestrian / #GameDev
+
+If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101850331907006641
+ 2019-04-01T09:58:50Z
+ 2019-04-01T09:58:50Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Me: I'm going to make this vital change to my world building in the morning, no way I'll forget this, it's too big of a deal<br />Also me: forgets</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849626603073336
+ 2019-04-01T06:59:28Z
+ 2019-04-01T06:59:28Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p><span class="h-card"><a href="https://mastodon.social/@Fergant" class="u-url mention">@<span>Fergant</span></a></span> Dom är i stort sett religiös skrift vid det här laget 👏👏</p><p>har dock bara läst svenska översättningen, kanske är dags att jag läser dom på engelska</p>
+
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849580030237068
+ 2019-04-01T06:47:37Z
+ 2019-04-01T06:47:37Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>What's you people's favourite fantasy books? Give me some hot tips 🌞</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849550599949363
+ 2019-04-01T06:40:08Z
+ 2019-04-01T06:40:08Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Stick them legs out 💃 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849191533152720
+ 2019-04-01T05:08:49Z
+ 2019-04-01T05:08:49Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>long 🐱 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101849165031453009
+ 2019-04-01T05:02:05Z
+ 2019-04-01T05:02:05Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101846512530748693
+ 2019-03-31T17:47:31Z
+ 2019-03-31T17:47:31Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Hello look at this boy having a decent haircut for once <a href="https://mastodon.social/tags/mastohorses" class="mention hashtag" rel="tag">#<span>mastohorses</span></a> <a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag">#<span>equestrian</span></a></p>
+
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101846181093805500
+ 2019-03-31T16:23:14Z
+ 2019-03-31T16:23:14Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Sorry did I disturb the who-is-the-longest-cat competition ? <a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag">#<span>mastocats</span></a></p>
+
+
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101845897513133849
+ 2019-03-31T15:11:07Z
+ 2019-03-31T15:11:07Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ more earthsea ramblings
+ <p>I'm re-watching Tales from Earthsea for the first time since I read the books, and that Therru doesn't squash Cob like a spider, as Orm Embar did is a wasted opportunity tbh</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101841219051533307
+ 2019-03-30T19:21:19Z
+ 2019-03-30T19:21:19Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>I gave my cats some mackerel and they ate it all in 0.3 seconds, and now they won't stop meowing for more, and I'm tired plz shut up</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101839949762341381
+ 2019-03-30T13:58:31Z
+ 2019-03-30T13:58:31Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>yet I'm confused about this american dude with a gun, like the heck r ya doin in mah ghibli</p>
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101839928677863590
+ 2019-03-30T13:53:09Z
+ 2019-03-30T13:53:09Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>2 hours into Ni no Kuni 2 and I've already sold my soul to this game</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101836329521599438
+ 2019-03-29T22:37:51Z
+ 2019-03-29T22:37:51Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>Pippi Longstocking the original one-punch /man</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835905282948341
+ 2019-03-29T20:49:57Z
+ 2019-03-29T20:49:57Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>I've had so much wine I thought I had a 3rd brother</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835878059204660
+ 2019-03-29T20:43:02Z
+ 2019-03-29T20:43:02Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+
+ <p>ååååhhh booi</p>
+
+ public
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835848050598939
+ 2019-03-29T20:35:24Z
+ 2019-03-29T20:35:24Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ <p><span class="h-card"><a href="https://thraeryn.net/@thraeryn" class="u-url mention">@<span>thraeryn</span></a></span> if I spent 1 hour and a half watching this monstrosity, I need to</p>
+
+
+ public
+
+
+
+
+
+
+ https://mastodon.social/users/emelie/statuses/101835823138262290
+ 2019-03-29T20:29:04Z
+ 2019-03-29T20:29:04Z
+ New status by emelie
+ http://activitystrea.ms/schema/1.0/comment
+ http://activitystrea.ms/schema/1.0/post
+
+ medical, fluids mention
+ <p><span class="h-card"><a href="https://icosahedron.website/@Trev" class="u-url mention">@<span>Trev</span></a></span> *hugs* ✨</p>
+
+
+ public
+
+
+
+
+
+
diff --git a/test/fixtures/httpoison_mock/status.emelie.json b/test/fixtures/httpoison_mock/status.emelie.json
new file mode 100644
index 000000000..4aada0377
--- /dev/null
+++ b/test/fixtures/httpoison_mock/status.emelie.json
@@ -0,0 +1,64 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "sensitive": "as:sensitive",
+ "Hashtag": "as:Hashtag",
+ "toot": "http://joinmastodon.org/ns#",
+ "Emoji": "toot:Emoji",
+ "focalPoint": {
+ "@container": "@list",
+ "@id": "toot:focalPoint"
+ }
+ }
+ ],
+ "id": "https://mastodon.social/users/emelie/statuses/101849165031453009",
+ "type": "Note",
+ "summary": null,
+ "inReplyTo": null,
+ "published": "2019-04-01T05:02:05Z",
+ "url": "https://mastodon.social/@emelie/101849165031453009",
+ "attributedTo": "https://mastodon.social/users/emelie",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://mastodon.social/users/emelie/followers"
+ ],
+ "sensitive": false,
+ "atomUri": "https://mastodon.social/users/emelie/statuses/101849165031453009",
+ "inReplyToAtomUri": null,
+ "conversation": "tag:mastodon.social,2019-04-01:objectId=94350309:objectType=Conversation",
+ "content": "You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 #mastocats
",
+ "contentMap": {
+ "en": "You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 #mastocats
"
+ },
+ "attachment": [
+ {
+ "type": "Document",
+ "mediaType": "video/mp4",
+ "url": "https://files.mastodon.social/media_attachments/files/013/049/816/original/e7831178a5e0d6d4.mp4",
+ "name": null
+ }
+ ],
+ "tag": [
+ {
+ "type": "Hashtag",
+ "href": "https://mastodon.social/tags/mastocats",
+ "name": "#mastocats"
+ }
+ ],
+ "replies": {
+ "id": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies",
+ "type": "Collection",
+ "first": {
+ "type": "CollectionPage",
+ "partOf": "https://mastodon.social/users/emelie/statuses/101849165031453009/replies",
+ "items": []
+ }
+ }
+}
diff --git a/test/fixtures/httpoison_mock/webfinger_emelie.json b/test/fixtures/httpoison_mock/webfinger_emelie.json
new file mode 100644
index 000000000..0b61cb618
--- /dev/null
+++ b/test/fixtures/httpoison_mock/webfinger_emelie.json
@@ -0,0 +1,36 @@
+{
+ "aliases": [
+ "https://mastodon.social/@emelie",
+ "https://mastodon.social/users/emelie"
+ ],
+ "links": [
+ {
+ "href": "https://mastodon.social/@emelie",
+ "rel": "http://webfinger.net/rel/profile-page",
+ "type": "text/html"
+ },
+ {
+ "href": "https://mastodon.social/users/emelie.atom",
+ "rel": "http://schemas.google.com/g/2010#updates-from",
+ "type": "application/atom+xml"
+ },
+ {
+ "href": "https://mastodon.social/users/emelie",
+ "rel": "self",
+ "type": "application/activity+json"
+ },
+ {
+ "href": "https://mastodon.social/api/salmon/15657",
+ "rel": "salmon"
+ },
+ {
+ "href": "data:application/magic-public-key,RSA.u3CWs1oAJPE3ZJ9sj6Ut_Mu-mTE7MOijsQc8_6c73XVVuhIEomiozJIH7l8a7S1n5SYL4UuiwcubSOi7u1bbGpYnp5TYhN-Cxvq_P80V4_ncNIPSQzS49it7nSLeG5pA21lGPDA44huquES1un6p9gSmbTwngVX9oe4MYuUeh0Z7vijjU13Llz1cRq_ZgPQPgfz-2NJf-VeXnvyDZDYxZPVBBlrMl3VoGbu0M5L8SjY35559KCZ3woIvqRolcoHXfgvJMdPcJgSZVYxlCw3dA95q9jQcn6s87CPSUs7bmYEQCrDVn5m5NER5TzwBmP4cgJl9AaDVWQtRd4jFZNTxlQ==.AQAB",
+ "rel": "magic-public-key"
+ },
+ {
+ "rel": "http://ostatus.org/schema/1.0/subscribe",
+ "template": "https://mastodon.social/authorize_interaction?uri={uri}"
+ }
+ ],
+ "subject": "acct:emelie@mastodon.social"
+}
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 18f77f01a..e1a08315a 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -216,7 +216,7 @@ def oauth_app_factory do
redirect_uris: "https://example.com/callback",
scopes: ["read", "write", "follow", "push"],
website: "https://example.com",
- client_id: "aaabbb==",
+ client_id: Ecto.UUID.generate(),
client_secret: "aaa;/&bbb"
}
end
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index 78e8efc9d..d3b547d91 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -36,6 +36,43 @@ def get("https://osada.macgirvin.com/channel/mike", _, _, _) do
}}
end
+ def get("https://mastodon.social/users/emelie/statuses/101849165031453009", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/status.emelie.json")
+ }}
+ end
+
+ def get("https://mastodon.social/users/emelie", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/emelie.json")
+ }}
+ end
+
+ def get(
+ "https://mastodon.social/.well-known/webfinger?resource=https://mastodon.social/users/emelie",
+ _,
+ _,
+ _
+ ) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/webfinger_emelie.json")
+ }}
+ end
+
+ def get("https://mastodon.social/users/emelie.atom", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/httpoison_mock/emelie.atom")
+ }}
+ end
+
def get(
"https://osada.macgirvin.com/.well-known/webfinger?resource=acct:mike@osada.macgirvin.com",
_,
diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs
index 7b814d171..1030bd555 100644
--- a/test/tasks/user_test.exs
+++ b/test/tasks/user_test.exs
@@ -248,4 +248,14 @@ test "invite token is generated" do
assert message =~ "Generated"
end
end
+
+ describe "running delete_activities" do
+ test "activities are deleted" do
+ %{nickname: nickname} = insert(:user)
+
+ assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname])
+ assert_received {:mix_shell, :info, [message]}
+ assert message == "User #{nickname} statuses deleted."
+ end
+ end
end
diff --git a/test/user_test.exs b/test/user_test.exs
index 8cf2ba6ab..38712cebb 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -122,7 +122,7 @@ test "follow takes a user and another user" do
{:ok, user} = User.follow(user, followed)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
followed = User.get_by_ap_id(followed.ap_id)
assert followed.info.follower_count == 1
@@ -178,7 +178,7 @@ test "unfollow takes a user and another user" do
{:ok, user, _activity} = User.unfollow(user, followed)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.following == []
end
@@ -188,7 +188,7 @@ test "unfollow doesn't unfollow yourself" do
{:error, _} = User.unfollow(user, user)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.following == [user.ap_id]
end
@@ -200,6 +200,13 @@ test "test if a user is following another user" do
refute User.following?(followed, user)
end
+ test "fetches correct profile for nickname beginning with number" do
+ # Use old-style integer ID to try to reproduce the problem
+ user = insert(:user, %{id: 1080})
+ userwithnumbers = insert(:user, %{nickname: "#{user.id}garbage"})
+ assert userwithnumbers == User.get_cached_by_nickname_or_id(userwithnumbers.nickname)
+ end
+
describe "user registration" do
@full_user_data %{
bio: "A guy",
@@ -679,7 +686,7 @@ test "blocks tear down cyclical follow relationships" do
assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -697,7 +704,7 @@ test "blocks tear down blocker->blocked follow relationships" do
refute User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -715,7 +722,7 @@ test "blocks tear down blocked->blocker follow relationships" do
assert User.following?(blocked, blocker)
{:ok, blocker} = User.block(blocker, blocked)
- blocked = Repo.get(User, blocked.id)
+ blocked = User.get_by_id(blocked.id)
assert User.blocks?(blocker, blocked)
@@ -792,6 +799,16 @@ test ".deactivate can de-activate then re-activate a user" do
assert false == user.info.deactivated
end
+ test ".delete_user_activities deletes all create activities" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
+ {:ok, _} = User.delete_user_activities(user)
+
+ # TODO: Remove favorites, repeats, delete activities.
+ refute Activity.get_by_id(activity.id)
+ end
+
test ".delete deactivates a user, all follow relationships and all create activities" do
user = insert(:user)
followed = insert(:user)
@@ -809,9 +826,9 @@ test ".delete deactivates a user, all follow relationships and all create activi
{:ok, _} = User.delete(user)
- followed = Repo.get(User, followed.id)
- follower = Repo.get(User, follower.id)
- user = Repo.get(User, user.id)
+ followed = User.get_by_id(followed.id)
+ follower = User.get_by_id(follower.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated
@@ -820,7 +837,7 @@ test ".delete deactivates a user, all follow relationships and all create activi
# TODO: Remove favorites, repeats, delete activities.
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "get_public_key_for_ap_id fetches a user that's not in the db" do
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs
index a1e83b380..8dd8e7e0a 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/web/activity_pub/activity_pub_controller_test.exs
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
alias Pleroma.Activity
alias Pleroma.Instances
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.UserView
@@ -51,7 +50,7 @@ test "it returns a json representation of the user with accept application/json"
|> put_req_header("accept", "application/json")
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -66,7 +65,7 @@ test "it returns a json representation of the user with accept application/activ
|> put_req_header("accept", "application/activity+json")
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -84,7 +83,7 @@ test "it returns a json representation of the user with accept application/ld+js
)
|> get("/users/#{user.nickname}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
end
@@ -543,7 +542,7 @@ test "it works for more than 10 users", %{conn: conn} do
user = insert(:user)
Enum.each(1..15, fn _ ->
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
other_user = insert(:user)
User.follow(user, other_user)
end)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index ac5fbe0a9..17fec05b1 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -218,18 +218,18 @@ test "increases user note count only for public activities" do
user = insert(:user)
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"})
{:ok, _} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 2
end
@@ -322,7 +322,7 @@ test "doesn't return blocked activities" do
{:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
- activity_three = Repo.get(Activity, activity_three.id)
+ activity_three = Activity.get_by_id(activity_three.id)
activities =
ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@@ -380,7 +380,7 @@ test "doesn't return muted activities" do
{:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
{:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
%Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
- activity_three = Repo.get(Activity, activity_three.id)
+ activity_three = Activity.get_by_id(activity_three.id)
activities =
ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@@ -559,7 +559,7 @@ test "unliking a previously liked object" do
{:ok, _, _, object} = ActivityPub.unlike(user, object)
assert object.data["like_count"] == 0
- assert Repo.get(Activity, like_activity.id) == nil
+ assert Activity.get_by_id(like_activity.id) == nil
end
end
@@ -610,7 +610,7 @@ test "unannouncing a previously announced object" do
assert unannounce_activity.data["actor"] == user.ap_id
assert unannounce_activity.data["context"] == announce_activity.data["context"]
- assert Repo.get(Activity, announce_activity.id) == nil
+ assert Activity.get_by_id(announce_activity.id) == nil
end
end
@@ -635,16 +635,6 @@ test "works with base64 encoded images" do
end
end
- describe "fetch the latest Follow" do
- test "fetches the latest Follow activity" do
- %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
- follower = Repo.get_by(User, ap_id: activity.data["actor"])
- followed = Repo.get_by(User, ap_id: activity.data["object"])
-
- assert activity == Utils.fetch_latest_follow(follower, followed)
- end
- end
-
describe "fetching an object" do
test "it fetches an object" do
{:ok, object} =
@@ -749,7 +739,7 @@ test "it creates a delete activity and deletes the original object" do
assert delete.data["actor"] == note.data["actor"]
assert delete.data["object"] == note.data["object"]["id"]
- assert Repo.get(Activity, delete.id) != nil
+ assert Activity.get_by_id(delete.id) != nil
assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end
@@ -758,23 +748,23 @@ test "decrements user note count only for public activities" do
user = insert(:user, info: %{note_count: 10})
{:ok, a1} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"})
{:ok, a2} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"})
{:ok, a3} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"})
{:ok, a4} =
- CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "direct"})
+ CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"})
{:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
{:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 10
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 50e8e40bd..62b973c4f 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -461,7 +461,7 @@ test "it works for incoming deletes" do
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "it fails for incoming deletes with spoofed origin" do
@@ -481,7 +481,7 @@ test "it fails for incoming deletes with spoofed origin" do
:error = Transmogrifier.handle_incoming(data)
- assert Repo.get(Activity, activity.id)
+ assert Activity.get_by_id(activity.id)
end
test "it works for incoming unannounces with an existing notice" do
@@ -639,7 +639,7 @@ test "it works for incoming accepts which were pre-accepted" do
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -661,7 +661,7 @@ test "it works for incoming accepts which were orphaned" do
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -681,7 +681,7 @@ test "it works for incoming accepts which are referenced by IRI only" do
{:ok, activity} = Transmogrifier.handle_incoming(accept_data)
assert activity.data["object"] == follow_activity.data["id"]
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == true
end
@@ -700,7 +700,7 @@ test "it fails for incoming accepts which cannot be correlated" do
:error = Transmogrifier.handle_incoming(accept_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
refute User.following?(follower, followed) == true
end
@@ -719,7 +719,7 @@ test "it fails for incoming rejects which cannot be correlated" do
:error = Transmogrifier.handle_incoming(accept_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
refute User.following?(follower, followed) == true
end
@@ -744,7 +744,7 @@ test "it works for incoming rejects which are orphaned" do
{:ok, activity} = Transmogrifier.handle_incoming(reject_data)
refute activity.local
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == false
end
@@ -766,7 +766,7 @@ test "it works for incoming rejects which are referenced by IRI only" do
{:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
- follower = Repo.get(User, follower.id)
+ follower = User.get_by_id(follower.id)
assert User.following?(follower, followed) == false
end
@@ -1020,7 +1020,7 @@ test "it upgrades a user to activitypub" do
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 1
{:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
@@ -1031,10 +1031,10 @@ test "it upgrades a user to activitypub" do
# Wait for the background task
:timer.sleep(1000)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.note_count == 1
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
assert user.follower_address in activity.recipients
assert %{
@@ -1057,10 +1057,10 @@ test "it upgrades a user to activitypub" do
refute "..." in activity.recipients
- unrelated_activity = Repo.get(Activity, unrelated_activity.id)
+ unrelated_activity = Activity.get_by_id(unrelated_activity.id)
refute user.follower_address in unrelated_activity.recipients
- user_two = Repo.get(User, user_two.id)
+ user_two = User.get_by_id(user_two.id)
assert user.follower_address in user_two.following
refute "..." in user_two.following
end
diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs
index 2bd3ddf93..6b9961d82 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/web/activity_pub/utils_test.exs
@@ -1,10 +1,34 @@
defmodule Pleroma.Web.ActivityPub.UtilsTest do
use Pleroma.DataCase
+ alias Pleroma.Activity
+ alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ describe "fetch the latest Follow" do
+ test "fetches the latest Follow activity" do
+ %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
+ follower = Repo.get_by(User, ap_id: activity.data["actor"])
+ followed = Repo.get_by(User, ap_id: activity.data["object"])
+
+ assert activity == Utils.fetch_latest_follow(follower, followed)
+ end
+ end
+
+ describe "fetch the latest Block" do
+ test "fetches the latest Block activity" do
+ blocker = insert(:user)
+ blocked = insert(:user)
+ {:ok, activity} = ActivityPub.block(blocker, blocked)
+
+ assert activity == Utils.fetch_latest_block(blocker, blocked)
+ end
+ end
+
describe "determine_explicit_mentions()" do
test "works with an object that has mentions" do
object = %{
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index 2f53416a3..acae64361 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -5,7 +5,6 @@
defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
use Pleroma.Web.ConnCase
- alias Pleroma.Repo
alias Pleroma.User
import Pleroma.Factory
@@ -101,13 +100,13 @@ test "it appends specified tags to users with specified nicknames", %{
user2: user2
} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user1.id).tags == ["x", "foo", "bar"]
- assert Repo.get(User, user2.id).tags == ["y", "foo", "bar"]
+ assert User.get_by_id(user1.id).tags == ["x", "foo", "bar"]
+ assert User.get_by_id(user2.id).tags == ["y", "foo", "bar"]
end
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user3.id).tags == ["unchanged"]
+ assert User.get_by_id(user3.id).tags == ["unchanged"]
end
end
@@ -137,13 +136,13 @@ test "it removes specified tags from users with specified nicknames", %{
user2: user2
} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user1.id).tags == []
- assert Repo.get(User, user2.id).tags == ["y"]
+ assert User.get_by_id(user1.id).tags == []
+ assert User.get_by_id(user2.id).tags == ["y"]
end
test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
assert json_response(conn, :no_content)
- assert Repo.get(User, user3.id).tags == ["unchanged"]
+ assert User.get_by_id(user3.id).tags == ["unchanged"]
end
end
@@ -213,7 +212,7 @@ test "deactivates the user", %{conn: conn} do
conn
|> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated == true
assert json_response(conn, :no_content)
end
@@ -225,7 +224,7 @@ test "activates the user", %{conn: conn} do
conn
|> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: true})
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
assert user.info.deactivated == false
assert json_response(conn, :no_content)
end
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs
index e04b9f9b5..f0c59d5c3 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/web/common_api/common_api_utils_test.exs
@@ -153,4 +153,40 @@ test "returns an existing mapping for an existing object" do
assert conversation_id == object.id
end
end
+
+ describe "formats date to asctime" do
+ test "when date is in ISO 8601 format" do
+ date = DateTime.utc_now() |> DateTime.to_iso8601()
+
+ expected =
+ date
+ |> DateTime.from_iso8601()
+ |> elem(1)
+ |> Calendar.Strftime.strftime!("%a %b %d %H:%M:%S %z %Y")
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+
+ test "when date is a binary in wrong format" do
+ date = DateTime.utc_now()
+
+ expected = ""
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+
+ test "when date is a Unix timestamp" do
+ date = DateTime.utc_now() |> DateTime.to_unix()
+
+ expected = ""
+
+ assert Utils.date_to_asctime(date) == expected
+ end
+
+ test "when date is nil" do
+ expected = ""
+
+ assert Utils.date_to_asctime(nil) == expected
+ end
+ end
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..6060cc97f 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -101,7 +101,7 @@ test "posting a status", %{conn: conn} do
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
json_response(conn_one, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
conn_two =
conn
@@ -140,7 +140,56 @@ test "posting a sensitive status", %{conn: conn} do
|> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
+ end
+
+ test "posting a fake status", %{conn: conn} do
+ user = insert(:user)
+
+ real_conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
+ })
+
+ real_status = json_response(real_conn, 200)
+
+ assert real_status
+ assert Object.get_by_ap_id(real_status["uri"])
+
+ real_status =
+ real_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ fake_conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
+ "preview" => true
+ })
+
+ fake_status = json_response(fake_conn, 200)
+
+ assert fake_status
+ refute Object.get_by_ap_id(fake_status["uri"])
+
+ fake_status =
+ fake_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ assert real_status == fake_status
end
test "posting a status with OGP link preview", %{conn: conn} do
@@ -155,7 +204,7 @@ test "posting a status with OGP link preview", %{conn: conn} do
})
assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
- assert Repo.get(Activity, id)
+ assert Activity.get_by_id(id)
Pleroma.Config.put([:rich_media, :enabled], false)
end
@@ -170,7 +219,7 @@ test "posting a direct status", %{conn: conn} do
|> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
- assert activity = Repo.get(Activity, id)
+ assert activity = Activity.get_by_id(id)
assert activity.recipients == [user2.ap_id, user1.ap_id]
assert activity.data["to"] == [user2.ap_id]
assert activity.data["cc"] == []
@@ -289,7 +338,7 @@ test "replying to a status", %{conn: conn} do
assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- activity = Repo.get(Activity, id)
+ activity = Activity.get_by_id(id)
assert activity.data["context"] == replied_to.data["context"]
assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
@@ -305,7 +354,7 @@ test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- activity = Repo.get(Activity, id)
+ activity = Activity.get_by_id(id)
assert activity
end
@@ -404,7 +453,7 @@ test "when you created it", %{conn: conn} do
assert %{} = json_response(conn, 200)
- refute Repo.get(Activity, activity.id)
+ refute Activity.get_by_id(activity.id)
end
test "when you didn't create it", %{conn: conn} do
@@ -418,7 +467,7 @@ test "when you didn't create it", %{conn: conn} do
assert %{"error" => _} = json_response(conn, 403)
- assert Repo.get(Activity, activity.id) == activity
+ assert Activity.get_by_id(activity.id) == activity
end
test "when you're an admin or moderator", %{conn: conn} do
@@ -441,8 +490,8 @@ test "when you're an admin or moderator", %{conn: conn} do
assert %{} = json_response(res_conn, 200)
- refute Repo.get(Activity, activity1.id)
- refute Repo.get(Activity, activity2.id)
+ refute Activity.get_by_id(activity1.id)
+ refute Activity.get_by_id(activity2.id)
end
end
@@ -1112,8 +1161,8 @@ test "/api/v1/follow_requests works" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1132,8 +1181,8 @@ test "/api/v1/follow_requests/:id/authorize works" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1145,8 +1194,8 @@ test "/api/v1/follow_requests/:id/authorize works" do
assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == true
end
@@ -1169,7 +1218,7 @@ test "/api/v1/follow_requests/:id/reject works" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1179,8 +1228,8 @@ test "/api/v1/follow_requests/:id/reject works" do
assert relationship = json_response(conn, 200)
assert to_string(other_user.id) == relationship["id"]
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
end
@@ -1465,7 +1514,7 @@ test "following / unfollowing a user", %{conn: conn} do
assert %{"id" => _id, "following" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1474,7 +1523,7 @@ test "following / unfollowing a user", %{conn: conn} do
assert %{"id" => _id, "following" => false} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1496,7 +1545,7 @@ test "muting / unmuting a user", %{conn: conn} do
assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1532,7 +1581,7 @@ test "blocking / unblocking a user", %{conn: conn} do
assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
conn =
build_conn()
@@ -1889,7 +1938,7 @@ test "get instance stats", %{conn: conn} do
{:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
# Stats should count users with missing or nil `info.deactivated` value
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
info_change = Changeset.change(user.info, %{deactivated: nil})
{:ok, _user} =
@@ -2265,4 +2314,30 @@ test "preserves parameters in link headers", %{conn: conn} do
assert link_header =~ ~r/max_id=#{notification1.id}/
end
end
+
+ test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
+ # Need to set an old-style integer ID to reproduce the problem
+ # (these are no longer assigned to new accounts but were preserved
+ # for existing accounts during the migration to flakeIDs)
+ user_one = insert(:user, %{id: 1212})
+ user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
+
+ resp_one =
+ conn
+ |> get("/api/v1/accounts/#{user_one.id}")
+
+ resp_two =
+ conn
+ |> get("/api/v1/accounts/#{user_two.nickname}")
+
+ resp_three =
+ conn
+ |> get("/api/v1/accounts/#{user_two.id}")
+
+ acc_one = json_response(resp_one, 200)
+ acc_two = json_response(resp_two, 200)
+ acc_three = json_response(resp_three, 200)
+ refute acc_one == acc_two
+ assert acc_two == acc_three
+ end
end
diff --git a/test/web/mastodon_api/notification_view_test.exs b/test/web/mastodon_api/notification_view_test.exs
index b826a7e61..f2c1eb76c 100644
--- a/test/web/mastodon_api/notification_view_test.exs
+++ b/test/web/mastodon_api/notification_view_test.exs
@@ -21,7 +21,7 @@ test "Mention notification" do
mentioned_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{mentioned_user.nickname}"})
{:ok, [notification]} = Notification.create_notifications(activity)
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
expected = %{
id: to_string(notification.id),
@@ -44,7 +44,7 @@ test "Favourite notification" do
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(favorite_activity)
- create_activity = Repo.get(Activity, create_activity.id)
+ create_activity = Activity.get_by_id(create_activity.id)
expected = %{
id: to_string(notification.id),
@@ -66,7 +66,7 @@ test "Reblog notification" do
{:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
{:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user)
{:ok, [notification]} = Notification.create_notifications(reblog_activity)
- reblog_activity = Repo.get(Activity, create_activity.id)
+ reblog_activity = Activity.get_by_id(create_activity.id)
expected = %{
id: to_string(notification.id),
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index e1c9b2c8f..8db92ac16 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -175,7 +175,7 @@ test "contains mentions" do
status = StatusView.render("status.json", %{activity: activity})
- actor = Repo.get_by(User, ap_id: activity.actor)
+ actor = User.get_by_ap_id(activity.actor)
assert status.mentions ==
Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 84ec7b4ee..a9a0b9ed4 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -10,261 +10,339 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- test "redirects with oauth authorization" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write", "follow"])
+ describe "GET /oauth/authorize" do
+ setup do
+ session_opts = [
+ store: :cookie,
+ key: "_test",
+ signing_salt: "cooldude"
+ ]
- conn =
- build_conn()
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "scope" => "read write",
- "state" => "statepassed"
- }
- })
-
- target = redirected_to(conn)
- assert target =~ app.redirect_uris
-
- query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
-
- assert %{"state" => "statepassed", "code" => code} = query
- auth = Repo.get_by(Authorization, token: code)
- assert auth
- assert auth.scopes == ["read", "write"]
- end
-
- test "returns 401 for wrong credentials", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app)
-
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "wrong",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => Enum.join(app.scopes, " ")
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "Invalid Username/Password"
- end
-
- test "returns 401 for missing scopes", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app)
-
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => ""
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "This action is outside the authorized scopes"
- end
-
- test "returns 401 for scopes beyond app scopes", %{conn: conn} do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write"])
-
- result =
- conn
- |> post("/oauth/authorize", %{
- "authorization" => %{
- "name" => user.nickname,
- "password" => "test",
- "client_id" => app.client_id,
- "redirect_uri" => app.redirect_uris,
- "state" => "statepassed",
- "scope" => "read write follow"
- }
- })
- |> html_response(:unauthorized)
-
- # Keep the details
- assert result =~ app.client_id
- assert result =~ app.redirect_uris
-
- # Error message
- assert result =~ "This action is outside the authorized scopes"
- end
-
- test "issues a token for an all-body request" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["read", "write"])
-
- {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
-
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
-
- assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
-
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == auth.scopes
- assert user.ap_id == ap_id
- end
-
- test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
- password = "testpassword"
- user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
-
- app = insert(:oauth_app, scopes: ["read", "write"])
-
- # Note: "scope" param is intentionally omitted
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "password",
- "username" => user.nickname,
- "password" => password,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
-
- assert %{"access_token" => token} = json_response(conn, 200)
-
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == app.scopes
- end
-
- test "issues a token for request with HTTP basic auth client credentials" do
- user = insert(:user)
- app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
-
- {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
- assert auth.scopes == ["scope1", "scope2"]
-
- app_encoded =
- (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
- |> Base.encode64()
-
- conn =
- build_conn()
- |> put_req_header("authorization", "Basic " <> app_encoded)
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris
- })
-
- assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
-
- assert scope == "scope1 scope2"
-
- token = Repo.get_by(Token, token: token)
- assert token
- assert token.scopes == ["scope1", "scope2"]
- end
-
- test "rejects token exchange with invalid client credentials" do
- user = insert(:user)
- app = insert(:oauth_app)
-
- {:ok, auth} = Authorization.create_authorization(app, user)
-
- conn =
- build_conn()
- |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => auth.token,
- "redirect_uri" => app.redirect_uris
- })
-
- assert resp = json_response(conn, 400)
- assert %{"error" => _} = resp
- refute Map.has_key?(resp, "access_token")
- end
-
- test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
- setting = Pleroma.Config.get([:instance, :account_activation_required])
-
- unless setting do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+ [
+ app: insert(:oauth_app, redirect_uris: "https://redirect.url"),
+ conn:
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(session_opts))
+ |> fetch_session()
+ ]
end
- password = "testpassword"
- user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
- info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
+ test "renders authentication page", %{app: app, conn: conn} do
+ conn =
+ get(
+ conn,
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read"
+ }
+ )
- {:ok, user} =
- user
- |> Ecto.Changeset.change()
- |> Ecto.Changeset.put_embed(:info, info_change)
- |> Repo.update()
+ assert html_response(conn, 200) =~ ~s(type="submit")
+ end
- refute Pleroma.User.auth_active?(user)
+ test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
+ %{app: app, conn: conn} do
+ token = insert(:oauth_token, app_id: app.id)
- app = insert(:oauth_app)
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read",
+ "force_login" => "true"
+ }
+ )
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "password",
- "username" => user.nickname,
- "password" => password,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
+ assert html_response(conn, 200) =~ ~s(type="submit")
+ end
- assert resp = json_response(conn, 403)
- assert %{"error" => _} = resp
- refute Map.has_key?(resp, "access_token")
+ test "redirects to app if user is already authenticated", %{app: app, conn: conn} do
+ token = insert(:oauth_token, app_id: app.id)
+
+ conn =
+ conn
+ |> put_session(:oauth_token, token.token)
+ |> get(
+ "/oauth/authorize",
+ %{
+ "response_type" => "code",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read"
+ }
+ )
+
+ assert redirected_to(conn) == "https://redirect.url"
+ end
end
- test "rejects an invalid authorization code" do
- app = insert(:oauth_app)
+ describe "POST /oauth/authorize" do
+ test "redirects with oauth authorization" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write", "follow"])
- conn =
- build_conn()
- |> post("/oauth/token", %{
- "grant_type" => "authorization_code",
- "code" => "Imobviouslyinvalid",
- "redirect_uri" => app.redirect_uris,
- "client_id" => app.client_id,
- "client_secret" => app.client_secret
- })
+ conn =
+ build_conn()
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "scope" => "read write",
+ "state" => "statepassed"
+ }
+ })
- assert resp = json_response(conn, 400)
- assert %{"error" => _} = json_response(conn, 400)
- refute Map.has_key?(resp, "access_token")
+ target = redirected_to(conn)
+ assert target =~ app.redirect_uris
+
+ query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+ assert %{"state" => "statepassed", "code" => code} = query
+ auth = Repo.get_by(Authorization, token: code)
+ assert auth
+ assert auth.scopes == ["read", "write"]
+ end
+
+ test "returns 401 for wrong credentials", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "wrong",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => Enum.join(app.scopes, " ")
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "Invalid Username/Password"
+ end
+
+ test "returns 401 for missing scopes", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => ""
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "This action is outside the authorized scopes"
+ end
+
+ test "returns 401 for scopes beyond app scopes", %{conn: conn} do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write"])
+
+ result =
+ conn
+ |> post("/oauth/authorize", %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "password" => "test",
+ "client_id" => app.client_id,
+ "redirect_uri" => app.redirect_uris,
+ "state" => "statepassed",
+ "scope" => "read write follow"
+ }
+ })
+ |> html_response(:unauthorized)
+
+ # Keep the details
+ assert result =~ app.client_id
+ assert result =~ app.redirect_uris
+
+ # Error message
+ assert result =~ "This action is outside the authorized scopes"
+ end
+ end
+
+ describe "POST /oauth/token" do
+ test "issues a token for an all-body request" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["read", "write"])
+
+ {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
+ "redirect_uri" => app.redirect_uris,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
+
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == auth.scopes
+ assert user.ap_id == ap_id
+ end
+
+ test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
+ password = "testpassword"
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+
+ app = insert(:oauth_app, scopes: ["read", "write"])
+
+ # Note: "scope" param is intentionally omitted
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert %{"access_token" => token} = json_response(conn, 200)
+
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == app.scopes
+ end
+
+ test "issues a token for request with HTTP basic auth client credentials" do
+ user = insert(:user)
+ app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
+
+ {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
+ assert auth.scopes == ["scope1", "scope2"]
+
+ app_encoded =
+ (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
+ |> Base.encode64()
+
+ conn =
+ build_conn()
+ |> put_req_header("authorization", "Basic " <> app_encoded)
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
+ "redirect_uri" => app.redirect_uris
+ })
+
+ assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
+
+ assert scope == "scope1 scope2"
+
+ token = Repo.get_by(Token, token: token)
+ assert token
+ assert token.scopes == ["scope1", "scope2"]
+ end
+
+ test "rejects token exchange with invalid client credentials" do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ {:ok, auth} = Authorization.create_authorization(app, user)
+
+ conn =
+ build_conn()
+ |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => auth.token,
+ "redirect_uri" => app.redirect_uris
+ })
+
+ assert resp = json_response(conn, 400)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
+ end
+
+ test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
+ setting = Pleroma.Config.get([:instance, :account_activation_required])
+
+ unless setting do
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+ on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+ end
+
+ password = "testpassword"
+ user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+ info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
+
+ {:ok, user} =
+ user
+ |> Ecto.Changeset.change()
+ |> Ecto.Changeset.put_embed(:info, info_change)
+ |> Repo.update()
+
+ refute Pleroma.User.auth_active?(user)
+
+ app = insert(:oauth_app)
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "password",
+ "username" => user.nickname,
+ "password" => password,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 403)
+ assert %{"error" => _} = resp
+ refute Map.has_key?(resp, "access_token")
+ end
+
+ test "rejects an invalid authorization code" do
+ app = insert(:oauth_app)
+
+ conn =
+ build_conn()
+ |> post("/oauth/token", %{
+ "grant_type" => "authorization_code",
+ "code" => "Imobviouslyinvalid",
+ "redirect_uri" => app.redirect_uris,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret
+ })
+
+ assert resp = json_response(conn, 400)
+ assert %{"error" => _} = json_response(conn, 400)
+ refute Map.has_key?(resp, "access_token")
+ end
end
end
diff --git a/test/web/ostatus/activity_representer_test.exs b/test/web/ostatus/activity_representer_test.exs
index 5cb135b4c..a4bb68c4d 100644
--- a/test/web/ostatus/activity_representer_test.exs
+++ b/test/web/ostatus/activity_representer_test.exs
@@ -116,10 +116,10 @@ test "an announce activity" do
{:ok, announce, _object} = ActivityPub.announce(user, object)
- announce = Repo.get(Activity, announce.id)
+ announce = Activity.get_by_id(announce.id)
note_user = User.get_cached_by_ap_id(note.data["actor"])
- note = Repo.get(Activity, note.id)
+ note = Activity.get_by_id(note.id)
note_xml =
ActivityRepresenter.to_simple_form(note, note_user, true)
diff --git a/test/web/ostatus/incoming_documents/delete_handling_test.exs b/test/web/ostatus/incoming_documents/delete_handling_test.exs
index 412d894fd..ca6e61339 100644
--- a/test/web/ostatus/incoming_documents/delete_handling_test.exs
+++ b/test/web/ostatus/incoming_documents/delete_handling_test.exs
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
alias Pleroma.Activity
alias Pleroma.Object
- alias Pleroma.Repo
alias Pleroma.Web.OStatus
setup do
@@ -32,10 +31,10 @@ test "it removes the mentioned activity" do
{:ok, [delete]} = OStatus.handle_incoming(incoming)
- refute Repo.get(Activity, note.id)
- refute Repo.get(Activity, like.id)
+ refute Activity.get_by_id(note.id)
+ refute Activity.get_by_id(like.id)
assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
- assert Repo.get(Activity, second_note.id)
+ assert Activity.get_by_id(second_note.id)
assert Object.get_by_ap_id(second_note.data["object"]["id"])
assert delete.data["type"] == "Delete"
diff --git a/test/web/ostatus/ostatus_test.exs b/test/web/ostatus/ostatus_test.exs
index 76b90e186..9fd100f63 100644
--- a/test/web/ostatus/ostatus_test.exs
+++ b/test/web/ostatus/ostatus_test.exs
@@ -154,7 +154,7 @@ test "handle incoming retweets - GS, subscription" do
assert "https://pleroma.soykaf.com/users/lain" in activity.data["to"]
refute activity.local
- retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+ retweeted_activity = Activity.get_by_id(retweeted_activity.id)
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
refute retweeted_activity.local
@@ -181,7 +181,7 @@ test "handle incoming retweets - GS, subscription - local message" do
assert user.ap_id in activity.data["to"]
refute activity.local
- retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+ retweeted_activity = Activity.get_by_id(retweeted_activity.id)
assert note_activity.id == retweeted_activity.id
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == user.ap_id
@@ -344,7 +344,7 @@ test "tries to use the information in poco fields" do
{:ok, user} = OStatus.find_or_make_user(uri)
- user = Repo.get(Pleroma.User, user.id)
+ user = Pleroma.User.get_by_id(user.id)
assert user.name == "Constance Variable"
assert user.nickname == "lambadalambda@social.heldscal.la"
assert user.local == false
diff --git a/test/web/salmon/salmon_test.exs b/test/web/salmon/salmon_test.exs
index 265e1abbd..35503259b 100644
--- a/test/web/salmon/salmon_test.exs
+++ b/test/web/salmon/salmon_test.exs
@@ -99,7 +99,7 @@ test "it pushes an activity to remote accounts it's addressed to" do
}
{:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]})
- user = Repo.get_by(User, ap_id: activity.data["actor"])
+ user = User.get_by_ap_id(activity.data["actor"])
{:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
poster = fn url, _data, _headers ->
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index 083540017..72b7ea85e 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -719,7 +719,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/create.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert User.ap_followers(followed) in current_user.following
assert json_response(conn, 200) ==
@@ -734,8 +734,8 @@ test "for restricted account", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/create.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
- followed = Repo.get(User, followed.id)
+ current_user = User.get_by_id(current_user.id)
+ followed = User.get_by_id(followed.id)
refute User.ap_followers(followed) in current_user.following
@@ -764,7 +764,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/friendships/destroy.json", %{user_id: followed.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert current_user.following == [current_user.ap_id]
assert json_response(conn, 200) ==
@@ -788,7 +788,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/blocks/create.json", %{user_id: blocked.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert User.blocks?(current_user, blocked)
assert json_response(conn, 200) ==
@@ -815,7 +815,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/blocks/destroy.json", %{user_id: blocked.id})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert current_user.info.blocks == []
assert json_response(conn, 200) ==
@@ -846,7 +846,7 @@ test "with credentials", %{conn: conn, user: current_user} do
|> with_credentials(current_user.nickname, "test")
|> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
- current_user = Repo.get(User, current_user.id)
+ current_user = User.get_by_id(current_user.id)
assert is_map(current_user.avatar)
assert json_response(conn, 200) ==
@@ -954,8 +954,8 @@ test "with credentials", %{conn: conn, user: current_user} do
|> 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"])
+ activity = Activity.get_by_id(note_activity.id)
+ activity_user = User.get_by_ap_id(note_activity.data["actor"])
assert json_response(response, 200) ==
ActivityView.render("activity.json", %{
@@ -992,8 +992,8 @@ test "with credentials", %{conn: conn, user: current_user} do
|> 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"])
+ activity = Activity.get_by_id(note_activity.id)
+ activity_user = User.get_by_ap_id(note_activity.data["actor"])
assert json_response(response, 200) ==
ActivityView.render("activity.json", %{
@@ -1021,7 +1021,7 @@ test "it creates a new user", %{conn: conn} do
user = json_response(conn, 200)
- fetched_user = Repo.get_by(User, nickname: "lain")
+ fetched_user = User.get_by_nickname("lain")
assert user == UserView.render("show.json", %{user: fetched_user})
end
@@ -1109,7 +1109,7 @@ test "it redirects to root url", %{conn: conn, user: user} do
test "it confirms the user account", %{conn: conn, user: user} do
get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
refute user.info.confirmation_pending
refute user.info.confirmation_token
@@ -1727,7 +1727,7 @@ test "with credentials, valid password and matching new password and confirmatio
})
assert json_response(conn, 200) == %{"status" => "success"}
- fetched_user = Repo.get(User, current_user.id)
+ fetched_user = User.get_by_id(current_user.id)
assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true
end
end
@@ -1768,8 +1768,8 @@ test "it lists friend requests" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1808,8 +1808,8 @@ test "it approves a friend request" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
@@ -1831,8 +1831,8 @@ test "it denies a friend request" do
{:ok, _activity} = ActivityPub.follow(other_user, user)
- user = Repo.get(User, user.id)
- other_user = Repo.get(User, other_user.id)
+ user = User.get_by_id(user.id)
+ other_user = User.get_by_id(other_user.id)
assert User.following?(other_user, user) == false
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs
index b823bfd68..6c00244de 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/web/twitter_api/twitter_api_test.exs
@@ -275,7 +275,7 @@ 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")
+ fetched_user = User.get_by_nickname("lain")
assert UserView.render("show.json", %{user: user}) ==
UserView.render("show.json", %{user: fetched_user})
@@ -293,7 +293,7 @@ test "it registers a new user with empty string in bio and returns the user." do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = Repo.get_by(User, nickname: "lain")
+ fetched_user = User.get_by_nickname("lain")
assert UserView.render("show.json", %{user: user}) ==
UserView.render("show.json", %{user: fetched_user})
@@ -369,7 +369,7 @@ test "it registers a new user via invite token and returns the user." do
{:ok, user} = TwitterAPI.register_user(data)
- fetched_user = Repo.get_by(User, nickname: "vinny")
+ fetched_user = User.get_by_nickname("vinny")
token = Repo.get_by(UserInviteToken, token: token.token)
assert token.used == true
@@ -393,7 +393,7 @@ test "it returns an error if invalid token submitted" do
{:error, msg} = TwitterAPI.register_user(data)
assert msg == "Invalid token"
- refute Repo.get_by(User, nickname: "GrimReaper")
+ refute User.get_by_nickname("GrimReaper")
end
@moduletag skip: "needs 'registrations_open: false' in config"
@@ -414,7 +414,7 @@ test "it returns an error if expired token submitted" do
{:error, msg} = TwitterAPI.register_user(data)
assert msg == "Expired token"
- refute Repo.get_by(User, nickname: "GrimReaper")
+ refute User.get_by_nickname("GrimReaper")
end
test "it returns the error on registration problems" do
@@ -429,7 +429,7 @@ test "it returns the error on registration problems" do
{:error, error_object} = TwitterAPI.register_user(data)
assert is_binary(error_object[:error])
- refute Repo.get_by(User, nickname: "lain")
+ refute User.get_by_nickname("lain")
end
test "it assigns an integer conversation_id" do
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs
index 832fdc096..e4dd97d46 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/web/twitter_api/util_controller_test.exs
@@ -6,6 +6,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
+ setup do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
describe "POST /api/pleroma/follow_import" do
test "it returns HTTP 200", %{conn: conn} do
user1 = insert(:user)
@@ -164,4 +169,26 @@ test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} d
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end
end
+
+ describe "GET /ostatus_subscribe?acct=...." do
+ test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
+ conn =
+ get(
+ conn,
+ "/ostatus_subscribe?acct=https://mastodon.social/users/emelie/statuses/101849165031453009"
+ )
+
+ assert redirected_to(conn) =~ "/notice/"
+ end
+
+ test "show follow account page if the `acct` is a account link", %{conn: conn} do
+ response =
+ get(
+ conn,
+ "/ostatus_subscribe?acct=https://mastodon.social/users/emelie"
+ )
+
+ assert html_response(response, 200) =~ "Log in to follow"
+ end
+ end
end
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index a1776b3e6..ee9a0c834 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -281,7 +281,7 @@ test "an announce activity" do
convo_id = Utils.context_to_conversation_id(activity.data["object"]["context"])
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
result = ActivityView.render("activity.json", activity: announce)
diff --git a/test/web/twitter_api/views/user_view_test.exs b/test/web/twitter_api/views/user_view_test.exs
index 4e7f94795..0feaf4b64 100644
--- a/test/web/twitter_api/views/user_view_test.exs
+++ b/test/web/twitter_api/views/user_view_test.exs
@@ -292,7 +292,7 @@ test "A blocked user for the blocker" do
}
}
- blocker = Repo.get(User, blocker.id)
+ blocker = User.get_by_id(blocker.id)
assert represented == UserView.render("show.json", %{user: user, for: blocker})
end