Merge branch 'develop' into csaurus/pleroma-feature/mstdn-direct-api
This commit is contained in:
commit
4b3ec53514
54 changed files with 1467 additions and 180 deletions
|
|
@ -5,6 +5,7 @@ defmodule Pleroma.Application do
|
|||
# for more information on OTP Applications
|
||||
def start(_type, _args) do
|
||||
import Supervisor.Spec
|
||||
import Cachex.Spec
|
||||
|
||||
# Define workers and child supervisors to be supervised
|
||||
children =
|
||||
|
|
@ -28,8 +29,11 @@ defmodule Pleroma.Application do
|
|||
[
|
||||
:idempotency_cache,
|
||||
[
|
||||
default_ttl: :timer.seconds(6 * 60 * 60),
|
||||
ttl_interval: :timer.seconds(60),
|
||||
expiration:
|
||||
expiration(
|
||||
default: :timer.seconds(6 * 60 * 60),
|
||||
interval: :timer.seconds(60)
|
||||
),
|
||||
limit: 2500
|
||||
]
|
||||
],
|
||||
|
|
|
|||
87
lib/pleroma/list.ex
Normal file
87
lib/pleroma/list.ex
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
defmodule Pleroma.List do
|
||||
use Ecto.Schema
|
||||
import Ecto.{Changeset, Query}
|
||||
alias Pleroma.{User, Repo}
|
||||
|
||||
schema "lists" do
|
||||
belongs_to(:user, Pleroma.User)
|
||||
field(:title, :string)
|
||||
field(:following, {:array, :string}, default: [])
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
def title_changeset(list, attrs \\ %{}) do
|
||||
list
|
||||
|> cast(attrs, [:title])
|
||||
|> validate_required([:title])
|
||||
end
|
||||
|
||||
def follow_changeset(list, attrs \\ %{}) do
|
||||
list
|
||||
|> cast(attrs, [:following])
|
||||
|> validate_required([:following])
|
||||
end
|
||||
|
||||
def for_user(user, opts) do
|
||||
query =
|
||||
from(
|
||||
l in Pleroma.List,
|
||||
where: l.user_id == ^user.id,
|
||||
order_by: [desc: l.id],
|
||||
limit: 50
|
||||
)
|
||||
|
||||
Repo.all(query)
|
||||
end
|
||||
|
||||
def get(id, %{id: user_id} = _user) do
|
||||
query =
|
||||
from(
|
||||
l in Pleroma.List,
|
||||
where: l.id == ^id,
|
||||
where: l.user_id == ^user_id
|
||||
)
|
||||
|
||||
Repo.one(query)
|
||||
end
|
||||
|
||||
def get_following(%Pleroma.List{following: following} = list) do
|
||||
q =
|
||||
from(
|
||||
u in User,
|
||||
where: u.follower_address in ^following
|
||||
)
|
||||
|
||||
{:ok, Repo.all(q)}
|
||||
end
|
||||
|
||||
def rename(%Pleroma.List{} = list, title) do
|
||||
list
|
||||
|> title_changeset(%{title: title})
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
def create(title, %User{} = creator) do
|
||||
list = %Pleroma.List{user_id: creator.id, title: title}
|
||||
Repo.insert(list)
|
||||
end
|
||||
|
||||
def follow(%Pleroma.List{following: following} = list, %User{} = followed) do
|
||||
update_follows(list, %{following: Enum.uniq([followed.follower_address | following])})
|
||||
end
|
||||
|
||||
def unfollow(%Pleroma.List{following: following} = list, %User{} = unfollowed) do
|
||||
update_follows(list, %{following: List.delete(following, unfollowed.follower_address)})
|
||||
end
|
||||
|
||||
def delete(%Pleroma.List{} = list) do
|
||||
Repo.delete(list)
|
||||
end
|
||||
|
||||
def update_follows(%Pleroma.List{} = list, attrs) do
|
||||
list
|
||||
|> follow_changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
end
|
||||
|
|
@ -33,19 +33,15 @@ defmodule Pleroma.Object do
|
|||
else
|
||||
key = "object:#{ap_id}"
|
||||
|
||||
Cachex.get!(
|
||||
:user_cache,
|
||||
key,
|
||||
fallback: fn _ ->
|
||||
object = get_by_ap_id(ap_id)
|
||||
Cachex.fetch!(:user_cache, key, fn _ ->
|
||||
object = get_by_ap_id(ap_id)
|
||||
|
||||
if object do
|
||||
{:commit, object}
|
||||
else
|
||||
{:ignore, object}
|
||||
end
|
||||
if object do
|
||||
{:commit, object}
|
||||
else
|
||||
{:ignore, object}
|
||||
end
|
||||
)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
end
|
||||
|
||||
def call(conn, _opts) do
|
||||
user = Utils.normalize_actor(conn.params["actor"])
|
||||
user = Utils.get_ap_id(conn.params["actor"])
|
||||
Logger.debug("Checking sig for #{user}")
|
||||
[signature | _] = get_req_header(conn, "signature")
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ defmodule Pleroma.User do
|
|||
%{
|
||||
following_count: length(user.following) - oneself,
|
||||
note_count: user.info["note_count"] || 0,
|
||||
follower_count: user.info["follower_count"] || 0
|
||||
follower_count: user.info["follower_count"] || 0,
|
||||
locked: user.info["locked"] || false
|
||||
}
|
||||
end
|
||||
|
||||
|
|
@ -167,28 +168,62 @@ defmodule Pleroma.User do
|
|||
end
|
||||
end
|
||||
|
||||
def maybe_direct_follow(%User{} = follower, %User{info: info} = followed) do
|
||||
user_info = user_info(followed)
|
||||
|
||||
should_direct_follow =
|
||||
cond do
|
||||
# if the account is locked, don't pre-create the relationship
|
||||
user_info["locked"] == true ->
|
||||
false
|
||||
|
||||
# if the users are blocking each other, we shouldn't even be here, but check for it anyway
|
||||
User.blocks?(follower, followed) == true or User.blocks?(followed, follower) == true ->
|
||||
false
|
||||
|
||||
# if OStatus, then there is no three-way handshake to follow
|
||||
User.ap_enabled?(followed) != true ->
|
||||
true
|
||||
|
||||
# if there are no other reasons not to, just pre-create the relationship
|
||||
true ->
|
||||
true
|
||||
end
|
||||
|
||||
if should_direct_follow do
|
||||
follow(follower, followed)
|
||||
else
|
||||
follower
|
||||
end
|
||||
end
|
||||
|
||||
def follow(%User{} = follower, %User{info: info} = followed) do
|
||||
ap_followers = followed.follower_address
|
||||
|
||||
if following?(follower, followed) or info["deactivated"] do
|
||||
{:error, "Could not follow user: #{followed.nickname} is already on your list."}
|
||||
else
|
||||
if !followed.local && follower.local && !ap_enabled?(followed) do
|
||||
Websub.subscribe(follower, followed)
|
||||
end
|
||||
cond do
|
||||
following?(follower, followed) or info["deactivated"] ->
|
||||
{:error, "Could not follow user: #{followed.nickname} is already on your list."}
|
||||
|
||||
following =
|
||||
[ap_followers | follower.following]
|
||||
|> Enum.uniq()
|
||||
blocks?(followed, follower) ->
|
||||
{:error, "Could not follow user: #{followed.nickname} blocked you."}
|
||||
|
||||
true ->
|
||||
if !followed.local && follower.local && !ap_enabled?(followed) do
|
||||
Websub.subscribe(follower, followed)
|
||||
end
|
||||
|
||||
following =
|
||||
[ap_followers | follower.following]
|
||||
|> Enum.uniq()
|
||||
|
||||
follower =
|
||||
follower
|
||||
|> follow_changeset(%{following: following})
|
||||
|> update_and_set_cache
|
||||
|
||||
{:ok, _} = update_follower_count(followed)
|
||||
|
||||
follower =
|
||||
follower
|
||||
|> follow_changeset(%{following: following})
|
||||
|> update_and_set_cache
|
||||
|
||||
{:ok, _} = update_follower_count(followed)
|
||||
|
||||
follower
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -223,9 +258,9 @@ defmodule Pleroma.User do
|
|||
|
||||
def update_and_set_cache(changeset) do
|
||||
with {:ok, user} <- Repo.update(changeset) do
|
||||
Cachex.set(:user_cache, "ap_id:#{user.ap_id}", user)
|
||||
Cachex.set(:user_cache, "nickname:#{user.nickname}", user)
|
||||
Cachex.set(:user_cache, "user_info:#{user.id}", user_info(user))
|
||||
Cachex.put(:user_cache, "ap_id:#{user.ap_id}", user)
|
||||
Cachex.put(:user_cache, "nickname:#{user.nickname}", user)
|
||||
Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user))
|
||||
{:ok, user}
|
||||
else
|
||||
e -> e
|
||||
|
|
@ -239,12 +274,12 @@ defmodule Pleroma.User do
|
|||
|
||||
def get_cached_by_ap_id(ap_id) do
|
||||
key = "ap_id:#{ap_id}"
|
||||
Cachex.get!(:user_cache, key, fallback: fn _ -> get_by_ap_id(ap_id) end)
|
||||
Cachex.fetch!(:user_cache, key, fn _ -> get_by_ap_id(ap_id) end)
|
||||
end
|
||||
|
||||
def get_cached_by_nickname(nickname) do
|
||||
key = "nickname:#{nickname}"
|
||||
Cachex.get!(:user_cache, key, fallback: fn _ -> get_or_fetch_by_nickname(nickname) end)
|
||||
Cachex.fetch!(:user_cache, key, fn _ -> get_or_fetch_by_nickname(nickname) end)
|
||||
end
|
||||
|
||||
def get_by_nickname(nickname) do
|
||||
|
|
@ -260,7 +295,7 @@ defmodule Pleroma.User do
|
|||
|
||||
def get_cached_user_info(user) do
|
||||
key = "user_info:#{user.id}"
|
||||
Cachex.get!(:user_cache, key, fallback: fn _ -> user_info(user) end)
|
||||
Cachex.fetch!(:user_cache, key, fn _ -> user_info(user) end)
|
||||
end
|
||||
|
||||
def fetch_by_nickname(nickname) do
|
||||
|
|
|
|||
|
|
@ -104,6 +104,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
def reject(%{to: to, actor: actor, object: object} = params) do
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
|
||||
with data <- %{"to" => to, "type" => "Reject", "actor" => actor, "object" => object},
|
||||
{:ok, activity} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
|
|
@ -201,12 +212,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
def unfollow(follower, followed, local \\ true) do
|
||||
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||
{:ok, activity} <- insert(unfollow_data, local),
|
||||
:ok,
|
||||
maybe_federate(activity) do
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
|
@ -230,6 +240,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
def block(blocker, blocked, activity_id \\ nil, local \\ true) do
|
||||
follow_activity = fetch_latest_follow(blocker, blocked)
|
||||
|
||||
if follow_activity do
|
||||
unfollow(blocker, blocked, nil, local)
|
||||
end
|
||||
|
||||
with block_data <- make_block_data(blocker, blocked, activity_id),
|
||||
{:ok, activity} <- insert(block_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def unblock(blocker, blocked, activity_id \\ nil, local \\ true) do
|
||||
with %Activity{} = block_activity <- fetch_latest_block(blocker, blocked),
|
||||
unblock_data <- make_unblock_data(blocker, blocked, block_activity, activity_id),
|
||||
{:ok, activity} <- insert(unblock_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_activities_for_context(context, opts \\ %{}) do
|
||||
public = ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
|
||||
|
|
@ -476,6 +509,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
"url" => [%{"href" => data["image"]["url"]}]
|
||||
}
|
||||
|
||||
locked = data["manuallyApprovesFollowers"] || false
|
||||
data = Transmogrifier.maybe_fix_user_object(data)
|
||||
|
||||
user_data = %{
|
||||
|
|
@ -483,7 +517,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
info: %{
|
||||
"ap_enabled" => true,
|
||||
"source_data" => data,
|
||||
"banner" => banner
|
||||
"banner" => banner,
|
||||
"locked" => locked
|
||||
},
|
||||
avatar: avatar,
|
||||
nickname: "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
alias Pleroma.Activity
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
|
|
@ -145,6 +146,78 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
defp mastodon_follow_hack(%{"id" => id, "actor" => follower_id}, followed) do
|
||||
with true <- id =~ "follows",
|
||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follower_id),
|
||||
%Activity{} = activity <- Utils.fetch_latest_follow(follower, followed) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_ -> {:error, nil}
|
||||
end
|
||||
end
|
||||
|
||||
defp mastodon_follow_hack(_), do: {:error, nil}
|
||||
|
||||
defp get_follow_activity(follow_object, followed) do
|
||||
with object_id when not is_nil(object_id) <- Utils.get_ap_id(follow_object),
|
||||
{_, %Activity{} = activity} <- {:activity, Activity.get_by_ap_id(object_id)} do
|
||||
{:ok, activity}
|
||||
else
|
||||
# Can't find the activity. This might a Mastodon 2.3 "Accept"
|
||||
{:activity, nil} ->
|
||||
mastodon_follow_hack(follow_object, followed)
|
||||
|
||||
_ ->
|
||||
{:error, nil}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Accept", "object" => follow_object, "actor" => actor, "id" => id} = data
|
||||
) do
|
||||
with %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
||||
{:ok, activity} <-
|
||||
ActivityPub.accept(%{
|
||||
to: follow_activity.data["to"],
|
||||
type: "Accept",
|
||||
actor: followed.ap_id,
|
||||
object: follow_activity.data["id"],
|
||||
local: false
|
||||
}) do
|
||||
if not User.following?(follower, followed) do
|
||||
{:ok, follower} = User.follow(follower, followed)
|
||||
end
|
||||
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Reject", "object" => follow_object, "actor" => actor, "id" => id} = data
|
||||
) do
|
||||
with %User{} = followed <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
|
||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
|
||||
{:ok, activity} <-
|
||||
ActivityPub.accept(%{
|
||||
to: follow_activity.data["to"],
|
||||
type: "Accept",
|
||||
actor: followed.ap_id,
|
||||
object: follow_activity.data["id"],
|
||||
local: false
|
||||
}) do
|
||||
User.unfollow(follower, followed)
|
||||
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = _data
|
||||
) do
|
||||
|
|
@ -207,11 +280,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def handle_incoming(
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = _data
|
||||
) do
|
||||
object_id =
|
||||
case object_id do
|
||||
%{"id" => id} -> id
|
||||
id -> id
|
||||
end
|
||||
object_id = Utils.get_ap_id(object_id)
|
||||
|
||||
with %User{} = _actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <-
|
||||
|
|
@ -229,13 +298,68 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
"object" => %{"type" => "Announce", "object" => object_id},
|
||||
"actor" => actor,
|
||||
"id" => id
|
||||
} = data
|
||||
} = _data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <-
|
||||
get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||
{:ok, activity, _, _} <- ActivityPub.unannounce(actor, object, id, false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{
|
||||
"type" => "Undo",
|
||||
"object" => %{"type" => "Follow", "object" => followed},
|
||||
"actor" => follower,
|
||||
"id" => id
|
||||
} = _data
|
||||
) do
|
||||
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
|
||||
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
|
||||
{:ok, activity} <- ActivityPub.unfollow(follower, followed, id, false) do
|
||||
User.unfollow(follower, followed)
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
@ap_config Application.get_env(:pleroma, :activitypub)
|
||||
@accept_blocks Keyword.get(@ap_config, :accept_blocks)
|
||||
|
||||
def handle_incoming(
|
||||
%{
|
||||
"type" => "Undo",
|
||||
"object" => %{"type" => "Block", "object" => blocked},
|
||||
"actor" => blocker,
|
||||
"id" => id
|
||||
} = _data
|
||||
) do
|
||||
with true <- @accept_blocks,
|
||||
%User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
|
||||
%User{} = blocker <- User.get_or_fetch_by_ap_id(blocker),
|
||||
{:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do
|
||||
User.unblock(blocker, blocked)
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
def handle_incoming(
|
||||
%{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = data
|
||||
) do
|
||||
with true <- @accept_blocks,
|
||||
%User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
|
||||
%User{} = blocker = User.get_or_fetch_by_ap_id(blocker),
|
||||
{:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do
|
||||
User.unfollow(blocker, blocked)
|
||||
User.block(blocker, blocked)
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> :error
|
||||
end
|
||||
|
|
@ -247,7 +371,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
"object" => %{"type" => "Like", "object" => object_id},
|
||||
"actor" => actor,
|
||||
"id" => id
|
||||
} = data
|
||||
} = _data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <-
|
||||
|
|
@ -255,14 +379,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
{:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> :error
|
||||
_e -> :error
|
||||
end
|
||||
end
|
||||
|
||||
# TODO
|
||||
# Accept
|
||||
# Undo for non-Announce
|
||||
|
||||
def handle_incoming(_), do: :error
|
||||
|
||||
def get_obj_helper(id) do
|
||||
|
|
@ -516,10 +636,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def maybe_fix_user_url(data) do
|
||||
if is_map(data["url"]) do
|
||||
data = Map.put(data, "url", data["url"]["href"])
|
||||
Map.put(data, "url", data["url"]["href"])
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def maybe_fix_user_object(data) do
|
||||
|
|
|
|||
|
|
@ -7,18 +7,15 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|
||||
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
||||
# so figure out what the actor's URI is based on what we have.
|
||||
def normalize_actor(actor) do
|
||||
cond do
|
||||
is_binary(actor) ->
|
||||
actor
|
||||
|
||||
is_map(actor) ->
|
||||
actor["id"]
|
||||
def get_ap_id(object) do
|
||||
case object do
|
||||
%{"id" => id} -> id
|
||||
id -> id
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_params(params) do
|
||||
Map.put(params, "actor", normalize_actor(params["actor"]))
|
||||
Map.put(params, "actor", get_ap_id(params["actor"]))
|
||||
end
|
||||
|
||||
def make_json_ld_header do
|
||||
|
|
@ -238,11 +235,17 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
query =
|
||||
from(
|
||||
activity in Activity,
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'type' = 'Follow'",
|
||||
activity.data
|
||||
),
|
||||
where: activity.actor == ^follower_id,
|
||||
where:
|
||||
fragment(
|
||||
"? @> ?",
|
||||
activity.data,
|
||||
^%{type: "Follow", actor: follower_id, object: followed_id}
|
||||
^%{object: followed_id}
|
||||
),
|
||||
order_by: [desc: :id],
|
||||
limit: 1
|
||||
|
|
@ -260,7 +263,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
query =
|
||||
from(
|
||||
activity in Activity,
|
||||
where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
|
||||
where: activity.actor == ^actor,
|
||||
# this is to use the index
|
||||
where:
|
||||
fragment(
|
||||
|
|
@ -346,13 +349,61 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|
||||
#### Unfollow-related helpers
|
||||
|
||||
def make_unfollow_data(follower, followed, follow_activity) do
|
||||
%{
|
||||
def make_unfollow_data(follower, followed, follow_activity, activity_id) do
|
||||
data = %{
|
||||
"type" => "Undo",
|
||||
"actor" => follower.ap_id,
|
||||
"to" => [followed.ap_id],
|
||||
"object" => follow_activity.data["id"]
|
||||
"object" => follow_activity.data
|
||||
}
|
||||
|
||||
if activity_id, do: Map.put(data, "id", activity_id), else: data
|
||||
end
|
||||
|
||||
#### Block-related helpers
|
||||
def fetch_latest_block(%User{ap_id: blocker_id}, %User{ap_id: blocked_id}) do
|
||||
query =
|
||||
from(
|
||||
activity in Activity,
|
||||
where:
|
||||
fragment(
|
||||
"? ->> 'type' = 'Block'",
|
||||
activity.data
|
||||
),
|
||||
where: activity.actor == ^blocker_id,
|
||||
where:
|
||||
fragment(
|
||||
"? @> ?",
|
||||
activity.data,
|
||||
^%{object: blocked_id}
|
||||
),
|
||||
order_by: [desc: :id],
|
||||
limit: 1
|
||||
)
|
||||
|
||||
Repo.one(query)
|
||||
end
|
||||
|
||||
def make_block_data(blocker, blocked, activity_id) do
|
||||
data = %{
|
||||
"type" => "Block",
|
||||
"actor" => blocker.ap_id,
|
||||
"to" => [blocked.ap_id],
|
||||
"object" => blocked.ap_id
|
||||
}
|
||||
|
||||
if activity_id, do: Map.put(data, "id", activity_id), else: data
|
||||
end
|
||||
|
||||
def make_unblock_data(blocker, blocked, block_activity, activity_id) do
|
||||
data = %{
|
||||
"type" => "Undo",
|
||||
"actor" => blocker.ap_id,
|
||||
"to" => [blocked.ap_id],
|
||||
"object" => block_activity.data
|
||||
}
|
||||
|
||||
if activity_id, do: Map.put(data, "id", activity_id), else: data
|
||||
end
|
||||
|
||||
#### Create-related helpers
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"name" => user.name,
|
||||
"summary" => user.bio,
|
||||
"url" => user.ap_id,
|
||||
"manuallyApprovesFollowers" => false,
|
||||
"manuallyApprovesFollowers" => user.info["locked"] || false,
|
||||
"publicKey" => %{
|
||||
"id" => "#{user.ap_id}#main-key",
|
||||
"owner" => user.ap_id,
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
"context" => context,
|
||||
"attachment" => attachments,
|
||||
"actor" => actor,
|
||||
"tag" => tags |> Enum.map(fn {_, tag} -> tag end)
|
||||
"tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq()
|
||||
}
|
||||
|
||||
if inReplyTo do
|
||||
|
|
@ -187,9 +187,9 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def confirm_current_password(user, params) do
|
||||
def confirm_current_password(user, password) do
|
||||
with %User{local: true} = db_user <- Repo.get(User, user.id),
|
||||
true <- Pbkdf2.checkpw(params["password"], db_user.password_hash) do
|
||||
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
|
||||
{:ok, db_user}
|
||||
else
|
||||
_ -> {:error, "Invalid password."}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ defmodule Pleroma.Web.HTTPSignatures do
|
|||
def validate_conn(conn) do
|
||||
# TODO: How to get the right key and see if it is actually valid for that request.
|
||||
# For now, fetch the key for the actor.
|
||||
with actor_id <- Utils.normalize_actor(conn.params["actor"]),
|
||||
with actor_id <- Utils.get_ap_id(conn.params["actor"]),
|
||||
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
|
||||
if validate_conn(conn, public_key) do
|
||||
true
|
||||
else
|
||||
Logger.debug("Could not validate, re-fetching user and trying one more time")
|
||||
# Fetch user anew and try one more time
|
||||
with actor_id <- Utils.normalize_actor(conn.params["actor"]),
|
||||
with actor_id <- Utils.get_ap_id(conn.params["actor"]),
|
||||
{:ok, _user} <- ActivityPub.make_user_from_ap_id(actor_id),
|
||||
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
|
||||
validate_conn(conn, public_key)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
use Pleroma.Web, :controller
|
||||
alias Pleroma.{Repo, Activity, User, Notification, Stats}
|
||||
alias Pleroma.Web
|
||||
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView}
|
||||
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.{CommonAPI, OStatus}
|
||||
alias Pleroma.Web.OAuth.{Authorization, Token, App}
|
||||
|
|
@ -284,11 +284,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
{:ok, activity} =
|
||||
Cachex.get!(
|
||||
:idempotency_cache,
|
||||
idempotency_key,
|
||||
fallback: fn _ -> CommonAPI.post(user, params) end
|
||||
)
|
||||
Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> CommonAPI.post(user, params) end)
|
||||
|
||||
render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
|
||||
end
|
||||
|
|
@ -442,7 +438,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
||||
with %User{} = followed <- Repo.get(User, id),
|
||||
{:ok, follower} <- User.follow(follower, followed),
|
||||
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
|
||||
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
|
||||
render(conn, AccountView, "relationship.json", %{user: follower, target: followed})
|
||||
else
|
||||
|
|
@ -455,7 +451,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
|
||||
with %User{} = followed <- Repo.get_by(User, nickname: uri),
|
||||
{:ok, follower} <- User.follow(follower, followed),
|
||||
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
|
||||
{:ok, _activity} <- ActivityPub.follow(follower, followed) do
|
||||
render(conn, AccountView, "account.json", %{user: followed})
|
||||
else
|
||||
|
|
@ -466,24 +462,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
# TODO: Clean up and unify
|
||||
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
||||
with %User{} = followed <- Repo.get(User, id),
|
||||
{:ok, follower, follow_activity} <- User.unfollow(follower, followed),
|
||||
{:ok, _activity} <-
|
||||
ActivityPub.insert(%{
|
||||
"type" => "Undo",
|
||||
"actor" => follower.ap_id,
|
||||
# get latest Follow for these users
|
||||
"object" => follow_activity.data["id"]
|
||||
}) do
|
||||
{:ok, _activity} <- ActivityPub.unfollow(follower, followed),
|
||||
{:ok, follower, _} <- User.unfollow(follower, followed) do
|
||||
render(conn, AccountView, "relationship.json", %{user: follower, target: followed})
|
||||
end
|
||||
end
|
||||
|
||||
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
|
||||
with %User{} = blocked <- Repo.get(User, id),
|
||||
{:ok, blocker} <- User.block(blocker, blocked) do
|
||||
{:ok, blocker} <- User.block(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
|
||||
render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked})
|
||||
else
|
||||
{:error, message} ->
|
||||
|
|
@ -495,7 +485,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
|
||||
with %User{} = blocked <- Repo.get(User, id),
|
||||
{:ok, blocker} <- User.unblock(blocker, blocked) do
|
||||
{:ok, blocker} <- User.unblock(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
|
||||
render(conn, AccountView, "relationship.json", %{user: blocker, target: blocked})
|
||||
else
|
||||
{:error, message} ->
|
||||
|
|
@ -586,6 +577,102 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
|
||||
end
|
||||
|
||||
def get_lists(%{assigns: %{user: user}} = conn, opts) do
|
||||
lists = Pleroma.List.for_user(user, opts)
|
||||
res = ListView.render("lists.json", lists: lists)
|
||||
json(conn, res)
|
||||
end
|
||||
|
||||
def get_list(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user) do
|
||||
res = ListView.render("list.json", list: list)
|
||||
json(conn, res)
|
||||
else
|
||||
_e -> json(conn, "error")
|
||||
end
|
||||
end
|
||||
|
||||
def delete_list(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
|
||||
{:ok, _list} <- Pleroma.List.delete(list) do
|
||||
json(conn, %{})
|
||||
else
|
||||
_e ->
|
||||
json(conn, "error")
|
||||
end
|
||||
end
|
||||
|
||||
def create_list(%{assigns: %{user: user}} = conn, %{"title" => title}) do
|
||||
with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do
|
||||
res = ListView.render("list.json", list: list)
|
||||
json(conn, res)
|
||||
end
|
||||
end
|
||||
|
||||
def add_to_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_ids" => accounts}) do
|
||||
accounts
|
||||
|> Enum.each(fn account_id ->
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
|
||||
%User{} = followed <- Repo.get(User, account_id) do
|
||||
Pleroma.List.follow(list, followed)
|
||||
end
|
||||
end)
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def remove_from_list(%{assigns: %{user: user}} = conn, %{"id" => id, "account_ids" => accounts}) do
|
||||
accounts
|
||||
|> Enum.each(fn account_id ->
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
|
||||
%User{} = followed <- Repo.get(Pleroma.User, account_id) do
|
||||
Pleroma.List.unfollow(list, followed)
|
||||
end
|
||||
end)
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def list_accounts(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
|
||||
{:ok, users} = Pleroma.List.get_following(list) do
|
||||
render(conn, AccountView, "accounts.json", %{users: users, as: :user})
|
||||
end
|
||||
end
|
||||
|
||||
def rename_list(%{assigns: %{user: user}} = conn, %{"id" => id, "title" => title}) do
|
||||
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
|
||||
{:ok, list} <- Pleroma.List.rename(list, title) do
|
||||
res = ListView.render("list.json", list: list)
|
||||
json(conn, res)
|
||||
else
|
||||
_e ->
|
||||
json(conn, "error")
|
||||
end
|
||||
end
|
||||
|
||||
def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
|
||||
with %Pleroma.List{title: title, following: following} <- Pleroma.List.get(id, user) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("type", "Create")
|
||||
|> Map.put("blocking_user", user)
|
||||
|
||||
# adding title is a hack to not make empty lists function like a public timeline
|
||||
activities =
|
||||
ActivityPub.fetch_activities([title | following], params)
|
||||
|> Enum.reverse()
|
||||
|
||||
conn
|
||||
|> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Error."})
|
||||
end
|
||||
end
|
||||
|
||||
def index(%{assigns: %{user: user}} = conn, _params) do
|
||||
token =
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
username: hd(String.split(user.nickname, "@")),
|
||||
acct: user.nickname,
|
||||
display_name: user.name || user.nickname,
|
||||
locked: false,
|
||||
locked: user_info.locked,
|
||||
created_at: Utils.to_masto_date(user.inserted_at),
|
||||
followers_count: user_info.follower_count,
|
||||
following_count: user_info.following_count,
|
||||
|
|
|
|||
15
lib/pleroma/web/mastodon_api/views/list_view.ex
Normal file
15
lib/pleroma/web/mastodon_api/views/list_view.ex
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
defmodule Pleroma.Web.MastodonAPI.ListView do
|
||||
use Pleroma.Web, :view
|
||||
alias Pleroma.Web.MastodonAPI.ListView
|
||||
|
||||
def render("lists.json", %{lists: lists} = opts) do
|
||||
render_many(lists, ListView, "list.json", opts)
|
||||
end
|
||||
|
||||
def render("list.json", %{list: list}) do
|
||||
%{
|
||||
id: to_string(list.id),
|
||||
title: list.title
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -232,7 +232,12 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
|||
end
|
||||
|
||||
# Only undos of follow for now. Will need to get redone once there are more
|
||||
def to_simple_form(%{data: %{"type" => "Undo"}} = activity, user, with_author) do
|
||||
def to_simple_form(
|
||||
%{data: %{"type" => "Undo", "object" => %{"type" => "Follow"} = follow_activity}} =
|
||||
activity,
|
||||
user,
|
||||
with_author
|
||||
) do
|
||||
h = fn str -> [to_charlist(str)] end
|
||||
|
||||
updated_at = activity.data["published"]
|
||||
|
|
@ -240,34 +245,26 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
|
|||
|
||||
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
|
||||
|
||||
follow_activity =
|
||||
if is_map(activity.data["object"]) do
|
||||
Activity.get_by_ap_id(activity.data["object"]["id"])
|
||||
else
|
||||
Activity.get_by_ap_id(activity.data["object"])
|
||||
end
|
||||
|
||||
mentions = (activity.recipients || []) |> get_mentions
|
||||
follow_activity = Activity.get_by_ap_id(follow_activity["id"])
|
||||
|
||||
if follow_activity do
|
||||
[
|
||||
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
|
||||
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
|
||||
{:id, h.(activity.data["id"])},
|
||||
{:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
|
||||
{:content, [type: 'html'],
|
||||
['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
|
||||
{:published, h.(inserted_at)},
|
||||
{:updated, h.(updated_at)},
|
||||
{:"activity:object",
|
||||
[
|
||||
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
|
||||
{:id, h.(follow_activity.data["object"])},
|
||||
{:uri, h.(follow_activity.data["object"])}
|
||||
]},
|
||||
{:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
|
||||
] ++ mentions ++ author
|
||||
end
|
||||
[
|
||||
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
|
||||
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
|
||||
{:id, h.(activity.data["id"])},
|
||||
{:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
|
||||
{:content, [type: 'html'],
|
||||
['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
|
||||
{:published, h.(inserted_at)},
|
||||
{:updated, h.(updated_at)},
|
||||
{:"activity:object",
|
||||
[
|
||||
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
|
||||
{:id, h.(follow_activity.data["object"])},
|
||||
{:uri, h.(follow_activity.data["object"])}
|
||||
]},
|
||||
{:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
|
||||
] ++ mentions ++ author
|
||||
end
|
||||
|
||||
def to_simple_form(%{data: %{"type" => "Delete"}} = activity, user, with_author) do
|
||||
|
|
|
|||
17
lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
Normal file
17
lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
defmodule Pleroma.Web.OStatus.UnfollowHandler do
|
||||
alias Pleroma.Web.{XML, OStatus}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.User
|
||||
|
||||
def handle(entry, doc) do
|
||||
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
|
||||
id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry),
|
||||
followed_uri when not is_nil(followed_uri) <-
|
||||
XML.string_from_xpath("/entry/activity:object/id", entry),
|
||||
{:ok, followed} <- OStatus.find_or_make_user(followed_uri),
|
||||
{:ok, activity} <- ActivityPub.unfollow(actor, followed, id, false) do
|
||||
User.unfollow(actor, followed)
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.OStatus do
|
|||
alias Pleroma.{Repo, User, Web, Object, Activity}
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.{WebFinger, Websub}
|
||||
alias Pleroma.Web.OStatus.{FollowHandler, NoteHandler, DeleteHandler}
|
||||
alias Pleroma.Web.OStatus.{FollowHandler, UnfollowHandler, NoteHandler, DeleteHandler}
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
||||
def feed_path(user) do
|
||||
|
|
@ -47,6 +47,9 @@ defmodule Pleroma.Web.OStatus do
|
|||
'http://activitystrea.ms/schema/1.0/follow' ->
|
||||
with {:ok, activity} <- FollowHandler.handle(entry, doc), do: activity
|
||||
|
||||
'http://activitystrea.ms/schema/1.0/unfollow' ->
|
||||
with {:ok, activity} <- UnfollowHandler.handle(entry, doc), do: activity
|
||||
|
||||
'http://activitystrea.ms/schema/1.0/share' ->
|
||||
with {:ok, activity, retweeted_activity} <- handle_share(entry, doc),
|
||||
do: [activity, retweeted_activity]
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ defmodule Pleroma.Web.Router do
|
|||
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
|
||||
pipe_through(:authenticated_api)
|
||||
post("/follow_import", UtilController, :follow_import)
|
||||
post("/change_password", UtilController, :change_password)
|
||||
post("/delete_account", UtilController, :delete_account)
|
||||
end
|
||||
|
||||
|
|
@ -103,7 +104,6 @@ defmodule Pleroma.Web.Router do
|
|||
get("/domain_blocks", MastodonAPIController, :empty_array)
|
||||
get("/follow_requests", MastodonAPIController, :empty_array)
|
||||
get("/mutes", MastodonAPIController, :empty_array)
|
||||
get("/lists", MastodonAPIController, :empty_array)
|
||||
|
||||
get("/timelines/home", MastodonAPIController, :home_timeline)
|
||||
|
||||
|
|
@ -125,6 +125,15 @@ defmodule Pleroma.Web.Router do
|
|||
get("/notifications/:id", MastodonAPIController, :get_notification)
|
||||
|
||||
post("/media", MastodonAPIController, :upload)
|
||||
|
||||
get("/lists", MastodonAPIController, :get_lists)
|
||||
get("/lists/:id", MastodonAPIController, :get_list)
|
||||
delete("/lists/:id", MastodonAPIController, :delete_list)
|
||||
post("/lists", MastodonAPIController, :create_list)
|
||||
put("/lists/:id", MastodonAPIController, :rename_list)
|
||||
get("/lists/:id/accounts", MastodonAPIController, :list_accounts)
|
||||
post("/lists/:id/accounts", MastodonAPIController, :add_to_list)
|
||||
delete("/lists/:id/accounts", MastodonAPIController, :remove_from_list)
|
||||
end
|
||||
|
||||
scope "/api/web", Pleroma.Web.MastodonAPI do
|
||||
|
|
@ -142,6 +151,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
get("/timelines/public", MastodonAPIController, :public_timeline)
|
||||
get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
|
||||
get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
|
||||
|
||||
get("/statuses/:id", MastodonAPIController, :get_status)
|
||||
get("/statuses/:id/context", MastodonAPIController, :get_context)
|
||||
|
|
|
|||
|
|
@ -197,8 +197,31 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
json(conn, "job started")
|
||||
end
|
||||
|
||||
def change_password(%{assigns: %{user: user}} = conn, params) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||
{:ok, user} ->
|
||||
with {:ok, _user} <-
|
||||
User.reset_password(user, %{
|
||||
password: params["new_password"],
|
||||
password_confirmation: params["new_password_confirmation"]
|
||||
}) do
|
||||
json(conn, %{status: "success"})
|
||||
else
|
||||
{:error, changeset} ->
|
||||
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
||||
json(conn, %{error: "New password #{error}."})
|
||||
|
||||
_ ->
|
||||
json(conn, %{error: "Unable to change password."})
|
||||
end
|
||||
|
||||
{:error, msg} ->
|
||||
json(conn, %{error: msg})
|
||||
end
|
||||
end
|
||||
|
||||
def delete_account(%{assigns: %{user: user}} = conn, params) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, params) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||
{:ok, user} ->
|
||||
Task.start(fn -> User.delete(user) end)
|
||||
json(conn, %{status: "success"})
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
|
|||
) do
|
||||
created_at = created_at |> Utils.date_to_asctime()
|
||||
|
||||
text = "#{user.nickname} undid the action at #{undid_activity}"
|
||||
text = "#{user.nickname} undid the action at #{undid_activity["id"]}"
|
||||
|
||||
%{
|
||||
"id" => activity.id,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
|
||||
def follow(%User{} = follower, params) do
|
||||
with {:ok, %User{} = followed} <- get_user(params),
|
||||
{:ok, follower} <- User.follow(follower, followed),
|
||||
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
|
||||
{:ok, activity} <- ActivityPub.follow(follower, followed) do
|
||||
{:ok, follower, followed, activity}
|
||||
else
|
||||
|
|
@ -36,14 +36,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
def unfollow(%User{} = follower, params) do
|
||||
with {:ok, %User{} = unfollowed} <- get_user(params),
|
||||
{:ok, follower, follow_activity} <- User.unfollow(follower, unfollowed),
|
||||
{:ok, _activity} <-
|
||||
ActivityPub.insert(%{
|
||||
"type" => "Undo",
|
||||
"actor" => follower.ap_id,
|
||||
# get latest Follow for these users
|
||||
"object" => follow_activity.data["id"],
|
||||
"published" => make_date()
|
||||
}) do
|
||||
{:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed) do
|
||||
{:ok, follower, unfollowed}
|
||||
else
|
||||
err -> err
|
||||
|
|
@ -52,7 +45,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
|
||||
def block(%User{} = blocker, params) do
|
||||
with {:ok, %User{} = blocked} <- get_user(params),
|
||||
{:ok, blocker} <- User.block(blocker, blocked) do
|
||||
{:ok, blocker} <- User.block(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
|
||||
{:ok, blocker, blocked}
|
||||
else
|
||||
err -> err
|
||||
|
|
@ -61,7 +55,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
|
||||
def unblock(%User{} = blocker, params) do
|
||||
with {:ok, %User{} = blocked} <- get_user(params),
|
||||
{:ok, blocker} <- User.unblock(blocker, blocked) do
|
||||
{:ok, blocker} <- User.unblock(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
|
||||
{:ok, blocker, blocked}
|
||||
else
|
||||
err -> err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue