* 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 bd8922b77..dccf7b263 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -348,10 +348,10 @@
initial_timeout: 30,
max_retries: 5
-config :pleroma, Pleroma.Jobs,
- federator_incoming: [max_jobs: 50],
- federator_outgoing: [max_jobs: 50],
- mailer: [max_jobs: 10]
+config :pleroma_job_queue, :queues,
+ federator_incoming: 50,
+ federator_outgoing: 50,
+ mailer: 10
config :pleroma, :fetch_initial_posts,
enabled: false,
@@ -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/config/test.exs b/config/test.exs
index 3691e5bd1..6a7b9067e 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -48,7 +48,7 @@
config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock
-config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2]
+config :pleroma_job_queue, disabled: true
try do
import_config "test.secret.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/config.md b/docs/config.md
index c1246ee25..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
@@ -253,25 +291,25 @@ You can then do
curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken"
```
-## Pleroma.Jobs
+## :pleroma_job_queue
-A list of job queues and their settings.
+[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs.
-Job queue settings:
-
-* `max_jobs`: The maximum amount of parallel jobs running at the same time.
+Pleroma has the following queues:
+* `federator_outgoing` - Outgoing federation
+* `federator_incoming` - Incoming federation
+* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)
Example:
-```exs
-config :pleroma, Pleroma.Jobs,
- federator_incoming: [max_jobs: 50],
- federator_outgoing: [max_jobs: 50]
+```elixir
+config :pleroma_job_queue, :queues,
+ federator_incoming: 50,
+ federator_outgoing: 50
```
This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`.
-
## Pleroma.Web.Federator.RetryQueue
* `enabled`: If set to `true`, failed federation jobs will be retried
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/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/application.ex b/lib/pleroma/application.ex
index cc81e1805..782d1d589 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -110,7 +110,6 @@ def start(_type, _args) do
worker(Pleroma.Web.Federator.RetryQueue, []),
worker(Pleroma.Stats, []),
worker(Pleroma.Web.Push, []),
- worker(Pleroma.Jobs, []),
worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary)
] ++
streamer_child() ++
diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex
index f7e3aa78b..b384e6fec 100644
--- a/lib/pleroma/emails/mailer.ex
+++ b/lib/pleroma/emails/mailer.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Mailer do
use Swoosh.Mailer, otp_app: :pleroma
def deliver_async(email, config \\ []) do
- Pleroma.Jobs.enqueue(:mailer, __MODULE__, [:deliver_async, email, config])
+ PleromaJobQueue.enqueue(:mailer, __MODULE__, [:deliver_async, email, config])
end
def perform(:deliver_async, email, config), do: deliver(email, config)
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/jobs.ex b/lib/pleroma/jobs.ex
deleted file mode 100644
index 24b7e5e46..000000000
--- a/lib/pleroma/jobs.ex
+++ /dev/null
@@ -1,152 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Jobs do
- @moduledoc """
- A basic job queue
- """
- use GenServer
-
- require Logger
-
- def init(args) do
- {:ok, args}
- end
-
- def start_link do
- queues =
- Pleroma.Config.get(Pleroma.Jobs)
- |> Enum.map(fn {name, _} -> create_queue(name) end)
- |> Enum.into(%{})
-
- state = %{
- queues: queues,
- refs: %{}
- }
-
- GenServer.start_link(__MODULE__, state, name: __MODULE__)
- end
-
- def create_queue(name) do
- {name, {:sets.new(), []}}
- end
-
- @doc """
- Enqueues a job.
-
- Returns `:ok`.
-
- ## Arguments
-
- - `queue_name` - a queue name(must be specified in the config).
- - `mod` - a worker module (must have `perform` function).
- - `args` - a list of arguments for the `perform` function of the worker module.
- - `priority` - a job priority (`0` by default).
-
- ## Examples
-
- Enqueue `Module.perform/0` with `priority=1`:
-
- iex> Pleroma.Jobs.enqueue(:example_queue, Module, [])
- :ok
-
- Enqueue `Module.perform(:job_name)` with `priority=5`:
-
- iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:job_name], 5)
- :ok
-
- Enqueue `Module.perform(:another_job, data)` with `priority=1`:
-
- iex> data = "foobar"
- iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:another_job, data])
- :ok
-
- Enqueue `Module.perform(:foobar_job, :foo, :bar, 42)` with `priority=1`:
-
- iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:foobar_job, :foo, :bar, 42])
- :ok
-
- """
-
- def enqueue(queue_name, mod, args, priority \\ 1)
-
- if Mix.env() == :test do
- def enqueue(_queue_name, mod, args, _priority) do
- apply(mod, :perform, args)
- end
- else
- @spec enqueue(atom(), atom(), [any()], integer()) :: :ok
- def enqueue(queue_name, mod, args, priority) do
- GenServer.cast(__MODULE__, {:enqueue, queue_name, mod, args, priority})
- end
- end
-
- def handle_cast({:enqueue, queue_name, mod, args, priority}, state) do
- {running_jobs, queue} = state[:queues][queue_name]
-
- queue = enqueue_sorted(queue, {mod, args}, priority)
-
- state =
- state
- |> update_queue(queue_name, {running_jobs, queue})
- |> maybe_start_job(queue_name, running_jobs, queue)
-
- {:noreply, state}
- end
-
- def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do
- queue_name = state.refs[ref]
-
- {running_jobs, queue} = state[:queues][queue_name]
-
- running_jobs = :sets.del_element(ref, running_jobs)
-
- state =
- state
- |> remove_ref(ref)
- |> update_queue(queue_name, {running_jobs, queue})
- |> maybe_start_job(queue_name, running_jobs, queue)
-
- {:noreply, state}
- end
-
- def maybe_start_job(state, queue_name, running_jobs, queue) do
- if :sets.size(running_jobs) < Pleroma.Config.get([__MODULE__, queue_name, :max_jobs]) &&
- queue != [] do
- {{mod, args}, queue} = queue_pop(queue)
- {:ok, pid} = Task.start(fn -> apply(mod, :perform, args) end)
- mref = Process.monitor(pid)
-
- state
- |> add_ref(queue_name, mref)
- |> update_queue(queue_name, {:sets.add_element(mref, running_jobs), queue})
- else
- state
- end
- end
-
- def enqueue_sorted(queue, element, priority) do
- [%{item: element, priority: priority} | queue]
- |> Enum.sort_by(fn %{priority: priority} -> priority end)
- end
-
- def queue_pop([%{item: element} | queue]) do
- {element, queue}
- end
-
- defp add_ref(state, queue_name, ref) do
- refs = Map.put(state[:refs], ref, queue_name)
- Map.put(state, :refs, refs)
- end
-
- defp remove_ref(state, ref) do
- refs = Map.delete(state[:refs], ref)
- Map.put(state, :refs, refs)
- end
-
- defp update_queue(state, queue_name, data) do
- queues = Map.put(state[:queues], queue_name, data)
- Map.put(state, :queues, queues)
- end
-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/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/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index a4b1518de..0c614a883 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -354,7 +354,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 ->
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/utils.ex b/lib/pleroma/web/common_api/utils.ex
index f596f703b..40cea3090 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -31,7 +31,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
@@ -275,7 +275,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/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index 5e690ddb8..c47328e13 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -4,7 +4,6 @@
defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
- alias Pleroma.Jobs
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay
@@ -31,39 +30,39 @@ def init do
# Client API
def incoming_doc(doc) do
- Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
+ PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
end
def incoming_ap_doc(params) do
- Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
+ PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
end
def publish(activity, priority \\ 1) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
end
def publish_single_ap(params) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
end
def publish_single_websub(websub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
end
def verify_websub(websub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
end
def request_subscription(sub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
end
def refresh_subscriptions do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
end
def publish_single_salmon(params) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
end
# Job Worker Callbacks
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index eee4e7678..0de2cca4e 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)
@@ -1249,16 +1249,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 +1282,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 +1320,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 +1462,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 661430464..333f21a91 100644
--- a/mix.exs
+++ b/mix.exs
@@ -93,7 +93,8 @@ defp deps do
{:timex, "~> 3.5"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
- ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}
+ ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"},
+ {:pleroma_job_queue, "~> 0.2.0"}
]
end
diff --git a/mix.lock b/mix.lock
index 05eaa1d69..f401258e9 100644
--- a/mix.lock
+++ b/mix.lock
@@ -50,6 +50,7 @@
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"},
+ "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"},
"plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
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/jobs_test.exs b/test/jobs_test.exs
deleted file mode 100644
index d55c86ccc..000000000
--- a/test/jobs_test.exs
+++ /dev/null
@@ -1,83 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.JobsTest do
- use ExUnit.Case, async: true
-
- alias Jobs.WorkerMock
- alias Pleroma.Jobs
-
- setup do
- state = %{
- queues: Enum.into([Jobs.create_queue(:testing)], %{}),
- refs: %{}
- }
-
- [state: state]
- end
-
- test "creates queue" do
- queue = Jobs.create_queue(:foobar)
-
- assert {:foobar, set} = queue
- assert :set == elem(set, 0) |> elem(0)
- end
-
- test "enqueues an element according to priority" do
- queue = [%{item: 1, priority: 2}]
-
- new_queue = Jobs.enqueue_sorted(queue, 2, 1)
- assert new_queue == [%{item: 2, priority: 1}, %{item: 1, priority: 2}]
-
- new_queue = Jobs.enqueue_sorted(queue, 2, 3)
- assert new_queue == [%{item: 1, priority: 2}, %{item: 2, priority: 3}]
- end
-
- test "pop first item" do
- queue = [%{item: 2, priority: 1}, %{item: 1, priority: 2}]
-
- assert {2, [%{item: 1, priority: 2}]} = Jobs.queue_pop(queue)
- end
-
- test "enqueue a job", %{state: state} do
- assert {:noreply, new_state} =
- Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
-
- assert %{queues: %{testing: {running_jobs, []}}, refs: _} = new_state
- assert :sets.size(running_jobs) == 1
- assert [ref] = :sets.to_list(running_jobs)
- assert %{refs: %{^ref => :testing}} = new_state
- end
-
- test "max jobs setting", %{state: state} do
- max_jobs = Pleroma.Config.get([Jobs, :testing, :max_jobs])
-
- {:noreply, state} =
- Enum.reduce(1..(max_jobs + 1), {:noreply, state}, fn _, {:noreply, state} ->
- Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
- end)
-
- assert %{
- queues: %{
- testing:
- {running_jobs, [%{item: {WorkerMock, [:test_job, :foo, :bar]}, priority: 3}]}
- }
- } = state
-
- assert :sets.size(running_jobs) == max_jobs
- end
-
- test "remove job after it finished", %{state: state} do
- {:noreply, new_state} =
- Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
-
- %{queues: %{testing: {running_jobs, []}}} = new_state
- [ref] = :sets.to_list(running_jobs)
-
- assert {:noreply, %{queues: %{testing: {running_jobs, []}}, refs: %{}}} =
- Jobs.handle_info({:DOWN, ref, :process, nil, nil}, new_state)
-
- assert :sets.size(running_jobs) == 0
- end
-end
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/support/jobs_worker_mock.ex b/test/support/jobs_worker_mock.ex
deleted file mode 100644
index 0fb976d05..000000000
--- a/test/support/jobs_worker_mock.ex
+++ /dev/null
@@ -1,19 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Jobs.WorkerMock do
- require Logger
-
- def perform(:test_job, arg, arg2) do
- Logger.debug({:perform, :test_job, arg, arg2})
- end
-
- def perform(:test_job, payload) do
- Logger.debug({:perform, :test_job, payload})
- end
-
- def test_job(payload) do
- Pleroma.Jobs.enqueue(:testing, __MODULE__, [:test_job, payload])
- end
-end
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 5ff157e93..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
@@ -739,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
@@ -748,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/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/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index d9bcbf5a9..1f3b26880 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,7 @@ 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 status with OGP link preview", %{conn: conn} do
@@ -155,7 +155,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 +170,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 +289,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 +305,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 +404,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 +418,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 +441,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 +1112,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 +1132,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 +1145,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 +1169,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 +1179,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 +1465,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 +1474,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 +1496,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 +1532,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 +1889,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 +2265,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