Merge branch 'develop' into tests/mastodon_api_controller.ex
This commit is contained in:
commit
3d722dc200
66 changed files with 1500 additions and 1687 deletions
|
|
@ -510,7 +510,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
@spec fetch_latest_activity_id_for_context(String.t(), keyword() | map()) ::
|
||||
Pleroma.FlakeId.t() | nil
|
||||
FlakeId.Ecto.CompatType.t() | nil
|
||||
def fetch_latest_activity_id_for_context(context, opts \\ %{}) do
|
||||
context
|
||||
|> fetch_activities_for_context_query(Map.merge(%{"skip_preload" => true}, opts))
|
||||
|
|
@ -519,13 +519,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Repo.one()
|
||||
end
|
||||
|
||||
def fetch_public_activities(opts \\ %{}) do
|
||||
def fetch_public_activities(opts \\ %{}, pagination \\ :keyset) do
|
||||
opts = Map.drop(opts, ["user"])
|
||||
|
||||
[Pleroma.Constants.as_public()]
|
||||
|> fetch_activities_query(opts)
|
||||
|> restrict_unlisted()
|
||||
|> Pagination.fetch_paginated(opts)
|
||||
|> Pagination.fetch_paginated(opts, pagination)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
|
|
@ -834,7 +834,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp restrict_muted_reblogs(query, _), do: query
|
||||
|
||||
defp exclude_poll_votes(query, %{"include_poll_votes" => "true"}), do: query
|
||||
defp exclude_poll_votes(query, %{"include_poll_votes" => true}), do: query
|
||||
|
||||
defp exclude_poll_votes(query, _) do
|
||||
if has_named_binding?(query, :object) do
|
||||
|
|
@ -918,11 +918,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> exclude_poll_votes(opts)
|
||||
end
|
||||
|
||||
def fetch_activities(recipients, opts \\ %{}) do
|
||||
def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do
|
||||
list_memberships = Pleroma.List.memberships(opts["user"])
|
||||
|
||||
fetch_activities_query(recipients ++ list_memberships, opts)
|
||||
|> Pagination.fetch_paginated(opts)
|
||||
|> Pagination.fetch_paginated(opts, pagination)
|
||||
|> Enum.reverse()
|
||||
|> maybe_update_cc(list_memberships, opts["user"])
|
||||
end
|
||||
|
|
@ -953,10 +953,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
)
|
||||
end
|
||||
|
||||
def fetch_activities_bounded(recipients, recipients_with_public, opts \\ %{}) do
|
||||
def fetch_activities_bounded(
|
||||
recipients,
|
||||
recipients_with_public,
|
||||
opts \\ %{},
|
||||
pagination \\ :keyset
|
||||
) do
|
||||
fetch_activities_query([], opts)
|
||||
|> fetch_activities_bounded_query(recipients, recipients_with_public)
|
||||
|> Pagination.fetch_paginated(opts)
|
||||
|> Pagination.fetch_paginated(opts, pagination)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
|
|
@ -996,6 +1001,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
locked = data["manuallyApprovesFollowers"] || false
|
||||
data = Transmogrifier.maybe_fix_user_object(data)
|
||||
discoverable = data["discoverable"] || false
|
||||
|
||||
user_data = %{
|
||||
ap_id: data["id"],
|
||||
|
|
@ -1004,7 +1010,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
source_data: data,
|
||||
banner: banner,
|
||||
fields: fields,
|
||||
locked: locked
|
||||
locked: locked,
|
||||
discoverable: discoverable
|
||||
},
|
||||
avatar: avatar,
|
||||
name: data["name"],
|
||||
|
|
|
|||
|
|
@ -231,13 +231,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
end
|
||||
end
|
||||
|
||||
def outbox(conn, %{"nickname" => nickname} = params) do
|
||||
def outbox(conn, %{"nickname" => nickname, "page" => page?} = params)
|
||||
when page? in [true, "true"] do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nickname),
|
||||
{:ok, user} <- User.ensure_keys_present(user) do
|
||||
activities =
|
||||
if params["max_id"] do
|
||||
ActivityPub.fetch_user_activities(user, nil, %{
|
||||
"max_id" => params["max_id"],
|
||||
# This is a hack because postgres generates inefficient queries when filtering by
|
||||
# 'Answer', poll votes will be hidden by the visibility filter in this case anyway
|
||||
"include_poll_votes" => true,
|
||||
"limit" => 10
|
||||
})
|
||||
else
|
||||
ActivityPub.fetch_user_activities(user, nil, %{
|
||||
"limit" => 10,
|
||||
"include_poll_votes" => true
|
||||
})
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> put_view(UserView)
|
||||
|> render("activity_collection_page.json", %{
|
||||
activities: activities,
|
||||
iri: "#{user.ap_id}/outbox"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def outbox(conn, %{"nickname" => nickname}) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nickname),
|
||||
{:ok, user} <- User.ensure_keys_present(user) do
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> put_view(UserView)
|
||||
|> render("outbox.json", %{user: user, max_id: params["max_id"]})
|
||||
|> render("activity_collection.json", %{iri: "#{user.ap_id}/outbox"})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -315,12 +345,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|
||||
def read_inbox(
|
||||
%{assigns: %{user: %{nickname: nickname} = user}} = conn,
|
||||
%{"nickname" => nickname} = params
|
||||
) do
|
||||
%{"nickname" => nickname, "page" => page?} = params
|
||||
)
|
||||
when page? in [true, "true"] do
|
||||
activities =
|
||||
if params["max_id"] do
|
||||
ActivityPub.fetch_activities([user.ap_id | user.following], %{
|
||||
"max_id" => params["max_id"],
|
||||
"limit" => 10
|
||||
})
|
||||
else
|
||||
ActivityPub.fetch_activities([user.ap_id | user.following], %{"limit" => 10})
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> put_view(UserView)
|
||||
|> render("inbox.json", user: user, max_id: params["max_id"])
|
||||
|> render("activity_collection_page.json", %{
|
||||
activities: activities,
|
||||
iri: "#{user.ap_id}/inbox"
|
||||
})
|
||||
end
|
||||
|
||||
def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{
|
||||
"nickname" => nickname
|
||||
}) do
|
||||
with {:ok, user} <- User.ensure_keys_present(user) do
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> put_view(UserView)
|
||||
|> render("activity_collection.json", %{iri: "#{user.ap_id}/inbox"})
|
||||
end
|
||||
end
|
||||
|
||||
def read_inbox(%{assigns: %{user: nil}} = conn, %{"nickname" => nickname}) do
|
||||
|
|
|
|||
|
|
@ -111,11 +111,11 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
@spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
|
||||
defp recipients(actor, activity) do
|
||||
{:ok, followers} =
|
||||
followers =
|
||||
if actor.follower_address in activity.recipients do
|
||||
User.get_external_followers(actor)
|
||||
else
|
||||
{:ok, []}
|
||||
[]
|
||||
end
|
||||
|
||||
fetchers =
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
alias Pleroma.Keys
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.Endpoint
|
||||
|
|
@ -107,7 +106,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
},
|
||||
"endpoints" => endpoints,
|
||||
"attachment" => fields,
|
||||
"tag" => (user.info.source_data["tag"] || []) ++ emoji_tags
|
||||
"tag" => (user.info.source_data["tag"] || []) ++ emoji_tags,
|
||||
"discoverable" => user.info.discoverable
|
||||
}
|
||||
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|
||||
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
|
||||
|
|
@ -210,20 +210,16 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
def render("outbox.json", %{user: user, max_id: max_qid}) do
|
||||
params = %{
|
||||
"limit" => "10"
|
||||
def render("activity_collection.json", %{iri: iri}) do
|
||||
%{
|
||||
"id" => iri,
|
||||
"type" => "OrderedCollection",
|
||||
"first" => "#{iri}?page=true"
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
params =
|
||||
if max_qid != nil do
|
||||
Map.put(params, "max_id", max_qid)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
activities = ActivityPub.fetch_user_activities(user, nil, params)
|
||||
|
||||
def render("activity_collection_page.json", %{activities: activities, iri: iri}) do
|
||||
# this is sorted chronologically, so first activity is the newest (max)
|
||||
{max_id, min_id, collection} =
|
||||
if length(activities) > 0 do
|
||||
|
|
@ -243,71 +239,14 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
}
|
||||
end
|
||||
|
||||
iri = "#{user.ap_id}/outbox"
|
||||
|
||||
page = %{
|
||||
"id" => "#{iri}?max_id=#{max_id}",
|
||||
%{
|
||||
"id" => "#{iri}?max_id=#{max_id}&page=true",
|
||||
"type" => "OrderedCollectionPage",
|
||||
"partOf" => iri,
|
||||
"orderedItems" => collection,
|
||||
"next" => "#{iri}?max_id=#{min_id}"
|
||||
"next" => "#{iri}?max_id=#{min_id}&page=true"
|
||||
}
|
||||
|
||||
if max_qid == nil do
|
||||
%{
|
||||
"id" => iri,
|
||||
"type" => "OrderedCollection",
|
||||
"first" => page
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
else
|
||||
page |> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
end
|
||||
|
||||
def render("inbox.json", %{user: user, max_id: max_qid}) do
|
||||
params = %{
|
||||
"limit" => "10"
|
||||
}
|
||||
|
||||
params =
|
||||
if max_qid != nil do
|
||||
Map.put(params, "max_id", max_qid)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
|
||||
|
||||
min_id = Enum.at(Enum.reverse(activities), 0).id
|
||||
max_id = Enum.at(activities, 0).id
|
||||
|
||||
collection =
|
||||
Enum.map(activities, fn act ->
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(act.data)
|
||||
data
|
||||
end)
|
||||
|
||||
iri = "#{user.ap_id}/inbox"
|
||||
|
||||
page = %{
|
||||
"id" => "#{iri}?max_id=#{max_id}",
|
||||
"type" => "OrderedCollectionPage",
|
||||
"partOf" => iri,
|
||||
"orderedItems" => collection,
|
||||
"next" => "#{iri}?max_id=#{min_id}"
|
||||
}
|
||||
|
||||
if max_qid == nil do
|
||||
%{
|
||||
"id" => iri,
|
||||
"type" => "OrderedCollection",
|
||||
"first" => page
|
||||
}
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
else
|
||||
page |> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
def collection(collection, iri, page, show_items \\ true, total \\ nil) do
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
alias Pleroma.Web.AdminAPI.ReportView
|
||||
alias Pleroma.Web.AdminAPI.Search
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.Endpoint
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.Router
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||
|
||||
|
|
@ -254,18 +256,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
"nickname" => nickname
|
||||
})
|
||||
when permission_group in ["moderator", "admin"] do
|
||||
user = User.get_cached_by_nickname(nickname)
|
||||
info = Map.put(%{}, "is_" <> permission_group, true)
|
||||
|
||||
info =
|
||||
%{}
|
||||
|> Map.put("is_" <> permission_group, true)
|
||||
|
||||
info_cng = User.Info.admin_api_update(user.info, info)
|
||||
|
||||
cng =
|
||||
user
|
||||
|> Ecto.Changeset.change()
|
||||
|> Ecto.Changeset.put_embed(:info, info_cng)
|
||||
{:ok, user} =
|
||||
nickname
|
||||
|> User.get_cached_by_nickname()
|
||||
|> User.update_info(&User.Info.admin_api_update(&1, info))
|
||||
|
||||
ModerationLog.insert_log(%{
|
||||
action: "grant",
|
||||
|
|
@ -274,8 +270,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
permission: permission_group
|
||||
})
|
||||
|
||||
{:ok, _user} = User.update_and_set_cache(cng)
|
||||
|
||||
json(conn, info)
|
||||
end
|
||||
|
||||
|
|
@ -293,40 +287,33 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
})
|
||||
end
|
||||
|
||||
def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
|
||||
render_error(conn, :forbidden, "You can't revoke your own admin status.")
|
||||
end
|
||||
|
||||
def right_delete(
|
||||
%{assigns: %{user: %User{:nickname => admin_nickname} = admin}} = conn,
|
||||
%{assigns: %{user: admin}} = conn,
|
||||
%{
|
||||
"permission_group" => permission_group,
|
||||
"nickname" => nickname
|
||||
}
|
||||
)
|
||||
when permission_group in ["moderator", "admin"] do
|
||||
if admin_nickname == nickname do
|
||||
render_error(conn, :forbidden, "You can't revoke your own admin status.")
|
||||
else
|
||||
user = User.get_cached_by_nickname(nickname)
|
||||
info = Map.put(%{}, "is_" <> permission_group, false)
|
||||
|
||||
info =
|
||||
%{}
|
||||
|> Map.put("is_" <> permission_group, false)
|
||||
{:ok, user} =
|
||||
nickname
|
||||
|> User.get_cached_by_nickname()
|
||||
|> User.update_info(&User.Info.admin_api_update(&1, info))
|
||||
|
||||
info_cng = User.Info.admin_api_update(user.info, info)
|
||||
ModerationLog.insert_log(%{
|
||||
action: "revoke",
|
||||
actor: admin,
|
||||
subject: user,
|
||||
permission: permission_group
|
||||
})
|
||||
|
||||
cng =
|
||||
Ecto.Changeset.change(user)
|
||||
|> Ecto.Changeset.put_embed(:info, info_cng)
|
||||
|
||||
{:ok, _user} = User.update_and_set_cache(cng)
|
||||
|
||||
ModerationLog.insert_log(%{
|
||||
action: "revoke",
|
||||
actor: admin,
|
||||
subject: user,
|
||||
permission: permission_group
|
||||
})
|
||||
|
||||
json(conn, info)
|
||||
end
|
||||
json(conn, info)
|
||||
end
|
||||
|
||||
def right_delete(conn, _) do
|
||||
|
|
@ -450,7 +437,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
{:ok, token} = Pleroma.PasswordResetToken.create_token(user)
|
||||
|
||||
conn
|
||||
|> json(token.token)
|
||||
|> json(%{
|
||||
token: token.token,
|
||||
link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
|
||||
})
|
||||
end
|
||||
|
||||
@doc "Force password reset for a given user"
|
||||
|
|
@ -463,13 +453,17 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
|
||||
def list_reports(conn, params) do
|
||||
{page, page_size} = page_params(params)
|
||||
|
||||
params =
|
||||
params
|
||||
|> Map.put("type", "Flag")
|
||||
|> Map.put("skip_preload", true)
|
||||
|> Map.put("total", true)
|
||||
|> Map.put("limit", page_size)
|
||||
|> Map.put("offset", (page - 1) * page_size)
|
||||
|
||||
reports = ActivityPub.fetch_activities([], params)
|
||||
reports = ActivityPub.fetch_activities([], params, :offset)
|
||||
|
||||
conn
|
||||
|> put_view(ReportView)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
alias Pleroma.Activity
|
||||
alias Pleroma.ActivityExpiration
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.ThreadMute
|
||||
alias Pleroma.User
|
||||
|
|
@ -261,12 +261,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
sensitive,
|
||||
poll
|
||||
),
|
||||
object <-
|
||||
Map.put(
|
||||
object,
|
||||
"emoji",
|
||||
Map.merge(Formatter.get_emoji_map(full_payload), poll_emoji)
|
||||
) do
|
||||
object <- put_emoji(object, full_payload, poll_emoji) do
|
||||
preview? = Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
|
||||
direct? = visibility == "direct"
|
||||
|
||||
|
|
@ -300,18 +295,25 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
# parse and put emoji to object data
|
||||
defp put_emoji(map, text, emojis) do
|
||||
Map.put(
|
||||
map,
|
||||
"emoji",
|
||||
Map.merge(Emoji.Formatter.get_emoji_map(text), emojis)
|
||||
)
|
||||
end
|
||||
|
||||
# Updates the emojis for a user based on their profile
|
||||
def update(user) do
|
||||
emoji = emoji_from_profile(user)
|
||||
source_data = user.info |> Map.get(:source_data, {}) |> Map.put("tag", emoji)
|
||||
|
||||
user =
|
||||
with emoji <- emoji_from_profile(user),
|
||||
source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji),
|
||||
info_cng <- User.Info.set_source_data(user.info, source_data),
|
||||
change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(change) do
|
||||
with {:ok, user} <- User.update_info(user, &User.Info.set_source_data(&1, source_data)) do
|
||||
user
|
||||
else
|
||||
_e ->
|
||||
user
|
||||
_e -> user
|
||||
end
|
||||
|
||||
ActivityPub.update(%{
|
||||
|
|
@ -336,34 +338,21 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
}
|
||||
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||
true <- Visibility.is_public?(activity),
|
||||
%{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity),
|
||||
changeset <-
|
||||
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
{:ok, _user} <- User.update_info(user, &User.Info.add_pinnned_activity(&1, activity)) do
|
||||
{:ok, activity}
|
||||
else
|
||||
%{errors: [pinned_activities: {err, _}]} ->
|
||||
{:error, err}
|
||||
|
||||
_ ->
|
||||
{:error, dgettext("errors", "Could not pin")}
|
||||
{:error, %{changes: %{info: %{errors: [pinned_activities: {err, _}]}}}} -> {:error, err}
|
||||
_ -> {:error, dgettext("errors", "Could not pin")}
|
||||
end
|
||||
end
|
||||
|
||||
def unpin(id_or_ap_id, user) do
|
||||
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
|
||||
%{valid?: true} = info_changeset <-
|
||||
User.Info.remove_pinnned_activity(user.info, activity),
|
||||
changeset <-
|
||||
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
{:ok, _user} <- User.update_info(user, &User.Info.remove_pinnned_activity(&1, activity)) do
|
||||
{:ok, activity}
|
||||
else
|
||||
%{errors: [pinned_activities: {err, _}]} ->
|
||||
{:error, err}
|
||||
|
||||
_ ->
|
||||
{:error, dgettext("errors", "Could not unpin")}
|
||||
%{errors: [pinned_activities: {err, _}]} -> {:error, err}
|
||||
_ -> {:error, dgettext("errors", "Could not unpin")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -458,23 +447,15 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
|
||||
defp set_visibility(activity, _), do: {:ok, activity}
|
||||
|
||||
def hide_reblogs(user, muted) do
|
||||
ap_id = muted.ap_id
|
||||
|
||||
def hide_reblogs(user, %{ap_id: ap_id} = _muted) do
|
||||
if ap_id not in user.info.muted_reblogs do
|
||||
info_changeset = User.Info.add_reblog_mute(user.info, ap_id)
|
||||
changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
|
||||
User.update_and_set_cache(changeset)
|
||||
User.update_info(user, &User.Info.add_reblog_mute(&1, ap_id))
|
||||
end
|
||||
end
|
||||
|
||||
def show_reblogs(user, muted) do
|
||||
ap_id = muted.ap_id
|
||||
|
||||
def show_reblogs(user, %{ap_id: ap_id} = _muted) do
|
||||
if ap_id in user.info.muted_reblogs do
|
||||
info_changeset = User.Info.remove_reblog_mute(user.info, ap_id)
|
||||
changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
|
||||
User.update_and_set_cache(changeset)
|
||||
User.update_info(user, &User.Info.remove_reblog_mute(&1, ap_id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
alias Pleroma.Activity
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Plugs.AuthenticationPlug
|
||||
|
|
@ -25,7 +26,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
# This is a hack for twidere.
|
||||
def get_by_id_or_ap_id(id) do
|
||||
activity =
|
||||
with true <- Pleroma.FlakeId.is_flake_id?(id),
|
||||
with true <- FlakeId.flake_id?(id),
|
||||
%Activity{} = activity <- Activity.get_by_id_with_object(id) do
|
||||
activity
|
||||
else
|
||||
|
|
@ -184,7 +185,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
"name" => option,
|
||||
"type" => "Note",
|
||||
"replies" => %{"type" => "Collection", "totalItems" => 0}
|
||||
}, Map.merge(emoji, Formatter.get_emoji_map(option))}
|
||||
}, Map.merge(emoji, Emoji.Formatter.get_emoji_map(option))}
|
||||
end)
|
||||
|
||||
case expires_in do
|
||||
|
|
@ -434,8 +435,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
|
||||
def emoji_from_profile(%{info: _info} = user) do
|
||||
(Formatter.get_emoji(user.bio) ++ Formatter.get_emoji(user.name))
|
||||
|> Enum.map(fn {shortcode, url, _} ->
|
||||
(Emoji.Formatter.get_emoji(user.bio) ++ Emoji.Formatter.get_emoji(user.name))
|
||||
|> Enum.map(fn {shortcode, %Emoji{file: url}} ->
|
||||
%{
|
||||
"type" => "Emoji",
|
||||
"icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{url}"},
|
||||
|
|
|
|||
|
|
@ -13,10 +13,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
alias Pleroma.Bookmark
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Filter
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.HTTP
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
|
|
@ -35,7 +34,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
alias Pleroma.Web.MastodonAPI.ListView
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
alias Pleroma.Web.MastodonAPI.MastodonView
|
||||
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||
alias Pleroma.Web.MastodonAPI.ReportView
|
||||
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
|
@ -141,7 +139,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
user_info_emojis =
|
||||
user.info
|
||||
|> Map.get(:emoji, [])
|
||||
|> Enum.concat(Formatter.get_emoji_map(emojis_text))
|
||||
|> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text))
|
||||
|> Enum.dedup()
|
||||
|
||||
info_params =
|
||||
|
|
@ -154,7 +152,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
:hide_follows,
|
||||
:hide_favorites,
|
||||
:show_role,
|
||||
:skip_thread_containment
|
||||
:skip_thread_containment,
|
||||
:discoverable
|
||||
]
|
||||
|> Enum.reduce(%{}, fn key, acc ->
|
||||
add_if_present(acc, params, to_string(key), key, fn value ->
|
||||
|
|
@ -189,14 +188,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end)
|
||||
|> Map.put(:emoji, user_info_emojis)
|
||||
|
||||
info_cng = User.Info.profile_update(user.info, info_params)
|
||||
changeset =
|
||||
user
|
||||
|> User.update_changeset(user_params)
|
||||
|> User.change_info(&User.Info.profile_update(&1, info_params))
|
||||
|
||||
with changeset <- User.update_changeset(user, user_params),
|
||||
changeset <- Changeset.put_embed(changeset, :info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
if original_user != user do
|
||||
CommonAPI.update(user)
|
||||
end
|
||||
with {:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
if original_user != user, do: CommonAPI.update(user)
|
||||
|
||||
json(
|
||||
conn,
|
||||
|
|
@ -226,12 +224,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do
|
||||
with new_info <- %{"banner" => %{}},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
CommonAPI.update(user)
|
||||
new_info = %{"banner" => %{}}
|
||||
|
||||
with {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
|
||||
CommonAPI.update(user)
|
||||
json(conn, %{url: nil})
|
||||
end
|
||||
end
|
||||
|
|
@ -239,9 +235,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
def update_banner(%{assigns: %{user: user}} = conn, params) do
|
||||
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
|
||||
new_info <- %{"banner" => object.data},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
{:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
|
||||
CommonAPI.update(user)
|
||||
%{"url" => [%{"href" => href} | _]} = object.data
|
||||
|
||||
|
|
@ -250,10 +244,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
|
||||
with new_info <- %{"background" => %{}},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
new_info = %{"background" => %{}}
|
||||
|
||||
with {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
|
||||
json(conn, %{url: nil})
|
||||
end
|
||||
end
|
||||
|
|
@ -261,9 +254,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
def update_background(%{assigns: %{user: user}} = conn, params) do
|
||||
with {:ok, object} <- ActivityPub.upload(params, type: :background),
|
||||
new_info <- %{"background" => object.data},
|
||||
info_cng <- User.Info.profile_update(user.info, new_info),
|
||||
changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
{:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
|
||||
%{"url" => [%{"href" => href} | _]} = object.data
|
||||
|
||||
json(conn, %{url: href})
|
||||
|
|
@ -334,7 +325,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
defp mastodonized_emoji do
|
||||
Pleroma.Emoji.get_all()
|
||||
|> Enum.map(fn {shortcode, relative_url, tags} ->
|
||||
|> Enum.map(fn {shortcode, %Pleroma.Emoji{file: relative_url, tags: tags}} ->
|
||||
url = to_string(URI.merge(Web.base_url(), relative_url))
|
||||
|
||||
%{
|
||||
|
|
@ -721,49 +712,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
def notifications(%{assigns: %{user: user}} = conn, params) do
|
||||
notifications = MastodonAPI.get_notifications(user, params)
|
||||
|
||||
conn
|
||||
|> add_link_headers(notifications)
|
||||
|> put_view(NotificationView)
|
||||
|> render("index.json", %{notifications: notifications, for: user})
|
||||
end
|
||||
|
||||
def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
||||
with {:ok, notification} <- Notification.get(user, id) do
|
||||
conn
|
||||
|> put_view(NotificationView)
|
||||
|> render("show.json", %{notification: notification, for: user})
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
def clear_notifications(%{assigns: %{user: user}} = conn, _params) do
|
||||
Notification.clear(user)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
||||
with {:ok, _notif} <- Notification.dismiss(user, id) do
|
||||
json(conn, %{})
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do
|
||||
Notification.destroy_multiple(user, ids)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
targets = User.get_all_by_ids(List.wrap(id))
|
||||
|
||||
|
|
@ -811,16 +759,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do
|
||||
with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)),
|
||||
%{} = attachment_data <- Map.put(object.data, "id", object.id),
|
||||
# Reject if not an image
|
||||
%{type: "image"} = rendered <-
|
||||
StatusView.render("attachment.json", %{attachment: attachment_data}),
|
||||
{:ok, _user} = User.update_mascot(user, rendered) do
|
||||
StatusView.render("attachment.json", %{attachment: attachment_data}) do
|
||||
# Sure!
|
||||
# Save to the user's info
|
||||
{:ok, _user} = User.update_info(user, &User.Info.mascot_update(&1, rendered))
|
||||
|
||||
json(conn, rendered)
|
||||
else
|
||||
%{type: _type} = _ ->
|
||||
render_error(conn, :unsupported_media_type, "mascots can only be images")
|
||||
|
||||
e ->
|
||||
e
|
||||
%{type: _} -> render_error(conn, :unsupported_media_type, "mascots can only be images")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -942,11 +890,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
|
||||
with {:ok, follow_requests} <- User.get_follow_requests(followed) do
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
|
||||
end
|
||||
follow_requests = User.get_follow_requests(followed)
|
||||
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
|
||||
end
|
||||
|
||||
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|
||||
|
|
@ -1348,11 +1296,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
|
||||
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
|
||||
info_cng = User.Info.mastodon_settings_update(user.info, settings)
|
||||
|
||||
with changeset <- Changeset.change(user),
|
||||
changeset <- Changeset.put_embed(changeset, :info, info_cng),
|
||||
{:ok, _user} <- User.update_and_set_cache(changeset) do
|
||||
with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do
|
||||
json(conn, %{})
|
||||
else
|
||||
e ->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
|
||||
# GET /api/v1/notifications
|
||||
def index(%{assigns: %{user: user}} = conn, params) do
|
||||
notifications = MastodonAPI.get_notifications(user, params)
|
||||
|
||||
conn
|
||||
|> add_link_headers(notifications)
|
||||
|> render("index.json", notifications: notifications, for: user)
|
||||
end
|
||||
|
||||
# GET /api/v1/notifications/:id
|
||||
def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with {:ok, notification} <- Notification.get(user, id) do
|
||||
render(conn, "show.json", notification: notification, for: user)
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
# POST /api/v1/notifications/clear
|
||||
def clear(%{assigns: %{user: user}} = conn, _params) do
|
||||
Notification.clear(user)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
# POST /api/v1/notifications/dismiss
|
||||
def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
||||
with {:ok, _notif} <- Notification.dismiss(user, id) do
|
||||
json(conn, %{})
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /api/v1/notifications/destroy_multiple
|
||||
def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do
|
||||
Notification.destroy_multiple(user, ids)
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
|
@ -116,6 +116,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
|
||||
relationship = render("relationship.json", %{user: opts[:for], target: user})
|
||||
|
||||
discoverable = user.info.discoverable
|
||||
|
||||
%{
|
||||
id: to_string(user.id),
|
||||
username: username_from_nickname(user.nickname),
|
||||
|
|
@ -139,7 +141,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
note: HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
|
||||
sensitive: false,
|
||||
fields: raw_fields,
|
||||
pleroma: %{}
|
||||
pleroma: %{
|
||||
discoverable: discoverable
|
||||
}
|
||||
},
|
||||
|
||||
# Pleroma extension
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Metadata.Utils do
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.Web.MediaProxy
|
||||
|
|
@ -13,7 +14,7 @@ defmodule Pleroma.Web.Metadata.Utils do
|
|||
|> HtmlEntities.decode()
|
||||
|> String.replace(~r/<br\s?\/?>/, " ")
|
||||
|> HTML.get_cached_stripped_html_for_activity(object, "metadata")
|
||||
|> Formatter.demojify()
|
||||
|> Emoji.Formatter.demojify()
|
||||
|> Formatter.truncate()
|
||||
end
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ defmodule Pleroma.Web.Metadata.Utils do
|
|||
|> HtmlEntities.decode()
|
||||
|> String.replace(~r/<br\s?\/?>/, " ")
|
||||
|> HTML.strip_tags()
|
||||
|> Formatter.demojify()
|
||||
|> Emoji.Formatter.demojify()
|
||||
|> Formatter.truncate(max_length)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
|
|||
field(:scopes, {:array, :string}, default: [])
|
||||
field(:valid_until, :naive_datetime_usec)
|
||||
field(:used, :boolean, default: false)
|
||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||
belongs_to(:app, App)
|
||||
|
||||
timestamps()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ defmodule Pleroma.Web.OAuth.Token do
|
|||
field(:refresh_token, :string)
|
||||
field(:scopes, {:array, :string}, default: [])
|
||||
field(:valid_until, :naive_datetime_usec)
|
||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||
belongs_to(:app, App)
|
||||
|
||||
timestamps()
|
||||
|
|
|
|||
|
|
@ -3,12 +3,33 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
|
|||
|
||||
require Logger
|
||||
|
||||
@emoji_dir_path Path.join(
|
||||
Pleroma.Config.get!([:instance, :static_dir]),
|
||||
"emoji"
|
||||
)
|
||||
def emoji_dir_path do
|
||||
Path.join(
|
||||
Pleroma.Config.get!([:instance, :static_dir]),
|
||||
"emoji"
|
||||
)
|
||||
end
|
||||
|
||||
@cache_seconds_per_file Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
|
||||
@doc """
|
||||
Lists packs from the remote instance.
|
||||
|
||||
Since JS cannot ask remote instances for their packs due to CPS, it has to
|
||||
be done by the server
|
||||
"""
|
||||
def list_from(conn, %{"instance_address" => address}) do
|
||||
address = String.trim(address)
|
||||
|
||||
if shareable_packs_available(address) do
|
||||
list_resp =
|
||||
"#{address}/api/pleroma/emoji/packs" |> Tesla.get!() |> Map.get(:body) |> Jason.decode!()
|
||||
|
||||
json(conn, list_resp)
|
||||
else
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: "The requested instance does not support sharing emoji packs"})
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Lists the packs available on the instance as JSON.
|
||||
|
|
@ -17,7 +38,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
|
|||
a map of "pack directory name" to pack.json contents.
|
||||
"""
|
||||
def list_packs(conn, _params) do
|
||||
with {:ok, results} <- File.ls(@emoji_dir_path) do
|
||||
# Create the directory first if it does not exist. This is probably the first request made
|
||||
# with the API so it should be sufficient
|
||||
with {:create_dir, :ok} <- {:create_dir, File.mkdir_p(emoji_dir_path())},
|
||||
{:ls, {:ok, results}} <- {:ls, File.ls(emoji_dir_path())} do
|
||||
pack_infos =
|
||||
results
|
||||
|> Enum.filter(&has_pack_json?/1)
|
||||
|
|
@ -28,24 +52,37 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
|
|||
|> Enum.into(%{})
|
||||
|
||||
json(conn, pack_infos)
|
||||
else
|
||||
{:create_dir, {:error, e}} ->
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: "Failed to create the emoji pack directory at #{emoji_dir_path()}: #{e}"})
|
||||
|
||||
{:ls, {:error, e}} ->
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{
|
||||
error:
|
||||
"Failed to get the contents of the emoji pack directory at #{emoji_dir_path()}: #{e}"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
defp has_pack_json?(file) do
|
||||
dir_path = Path.join(@emoji_dir_path, file)
|
||||
dir_path = Path.join(emoji_dir_path(), file)
|
||||
# Filter to only use the pack.json packs
|
||||
File.dir?(dir_path) and File.exists?(Path.join(dir_path, "pack.json"))
|
||||
end
|
||||
|
||||
defp load_pack(pack_name) do
|
||||
pack_path = Path.join(@emoji_dir_path, pack_name)
|
||||
pack_path = Path.join(emoji_dir_path(), pack_name)
|
||||
pack_file = Path.join(pack_path, "pack.json")
|
||||
|
||||
{pack_name, Jason.decode!(File.read!(pack_file))}
|
||||
end
|
||||
|
||||
defp validate_pack({name, pack}) do
|
||||
pack_path = Path.join(@emoji_dir_path, name)
|
||||
pack_path = Path.join(emoji_dir_path(), name)
|
||||
|
||||
if can_download?(pack, pack_path) do
|
||||
archive_for_sha = make_archive(name, pack, pack_path)
|
||||
|
|
@ -79,7 +116,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
|
|||
|
||||
{:ok, {_, zip_result}} = :zip.zip('#{name}.zip', files, [:memory, cwd: to_charlist(pack_dir)])
|
||||
|
||||
cache_ms = :timer.seconds(@cache_seconds_per_file * Enum.count(files))
|
||||
cache_seconds_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
|
||||
cache_ms = :timer.seconds(cache_seconds_per_file * Enum.count(files))
|
||||
|
||||
Cachex.put!(
|
||||
:emoji_packs_cache,
|
||||
|
|
@ -115,7 +153,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
to download packs that the instance shares.
|
||||
"""
|
||||
def download_shared(conn, %{"name" => name}) do
|
||||
pack_dir = Path.join(@emoji_dir_path, name)
|
||||
pack_dir = Path.join(emoji_dir_path(), name)
|
||||
pack_file = Path.join(pack_dir, "pack.json")
|
||||
|
||||
with {_, true} <- {:exists?, File.exists?(pack_file)},
|
||||
|
|
@ -139,6 +177,22 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
end
|
||||
end
|
||||
|
||||
defp shareable_packs_available(address) do
|
||||
"#{address}/.well-known/nodeinfo"
|
||||
|> Tesla.get!()
|
||||
|> Map.get(:body)
|
||||
|> Jason.decode!()
|
||||
|> Map.get("links")
|
||||
|> List.last()
|
||||
|> Map.get("href")
|
||||
# Get the actual nodeinfo address and fetch it
|
||||
|> Tesla.get!()
|
||||
|> Map.get(:body)
|
||||
|> Jason.decode!()
|
||||
|> get_in(["metadata", "features"])
|
||||
|> Enum.member?("shareable_emoji_packs")
|
||||
end
|
||||
|
||||
@doc """
|
||||
An admin endpoint to request downloading a pack named `pack_name` from the instance
|
||||
`instance_address`.
|
||||
|
|
@ -147,21 +201,9 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
from that instance, otherwise it will be downloaded from the fallback source, if there is one.
|
||||
"""
|
||||
def download_from(conn, %{"instance_address" => address, "pack_name" => name} = data) do
|
||||
shareable_packs_available =
|
||||
"#{address}/.well-known/nodeinfo"
|
||||
|> Tesla.get!()
|
||||
|> Map.get(:body)
|
||||
|> Jason.decode!()
|
||||
|> List.last()
|
||||
|> Map.get("href")
|
||||
# Get the actual nodeinfo address and fetch it
|
||||
|> Tesla.get!()
|
||||
|> Map.get(:body)
|
||||
|> Jason.decode!()
|
||||
|> get_in(["metadata", "features"])
|
||||
|> Enum.member?("shareable_emoji_packs")
|
||||
address = String.trim(address)
|
||||
|
||||
if shareable_packs_available do
|
||||
if shareable_packs_available(address) do
|
||||
full_pack =
|
||||
"#{address}/api/pleroma/emoji/packs/list"
|
||||
|> Tesla.get!()
|
||||
|
|
@ -195,7 +237,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
%{body: emoji_archive} <- Tesla.get!(uri),
|
||||
{_, true} <- {:checksum, Base.decode16!(sha) == :crypto.hash(:sha256, emoji_archive)} do
|
||||
local_name = data["as"] || name
|
||||
pack_dir = Path.join(@emoji_dir_path, local_name)
|
||||
pack_dir = Path.join(emoji_dir_path(), local_name)
|
||||
File.mkdir_p!(pack_dir)
|
||||
|
||||
files = Enum.map(full_pack["files"], fn {_, path} -> to_charlist(path) end)
|
||||
|
|
@ -233,7 +275,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
Creates an empty pack named `name` which then can be updated via the admin UI.
|
||||
"""
|
||||
def create(conn, %{"name" => name}) do
|
||||
pack_dir = Path.join(@emoji_dir_path, name)
|
||||
pack_dir = Path.join(emoji_dir_path(), name)
|
||||
|
||||
if not File.exists?(pack_dir) do
|
||||
File.mkdir_p!(pack_dir)
|
||||
|
|
@ -257,7 +299,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
Deletes the pack `name` and all it's files.
|
||||
"""
|
||||
def delete(conn, %{"name" => name}) do
|
||||
pack_dir = Path.join(@emoji_dir_path, name)
|
||||
pack_dir = Path.join(emoji_dir_path(), name)
|
||||
|
||||
case File.rm_rf(pack_dir) do
|
||||
{:ok, _} ->
|
||||
|
|
@ -276,7 +318,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
`new_data` is the new metadata for the pack, that will replace the old metadata.
|
||||
"""
|
||||
def update_metadata(conn, %{"pack_name" => name, "new_data" => new_data}) do
|
||||
pack_file_p = Path.join([@emoji_dir_path, name, "pack.json"])
|
||||
pack_file_p = Path.join([emoji_dir_path(), name, "pack.json"])
|
||||
|
||||
full_pack = Jason.decode!(File.read!(pack_file_p))
|
||||
|
||||
|
|
@ -360,7 +402,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
conn,
|
||||
%{"pack_name" => pack_name, "action" => "add", "shortcode" => shortcode} = params
|
||||
) do
|
||||
pack_dir = Path.join(@emoji_dir_path, pack_name)
|
||||
pack_dir = Path.join(emoji_dir_path(), pack_name)
|
||||
pack_file_p = Path.join(pack_dir, "pack.json")
|
||||
|
||||
full_pack = Jason.decode!(File.read!(pack_file_p))
|
||||
|
|
@ -408,7 +450,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
"action" => "remove",
|
||||
"shortcode" => shortcode
|
||||
}) do
|
||||
pack_dir = Path.join(@emoji_dir_path, pack_name)
|
||||
pack_dir = Path.join(emoji_dir_path(), pack_name)
|
||||
pack_file_p = Path.join(pack_dir, "pack.json")
|
||||
|
||||
full_pack = Jason.decode!(File.read!(pack_file_p))
|
||||
|
|
@ -443,7 +485,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
conn,
|
||||
%{"pack_name" => pack_name, "action" => "update", "shortcode" => shortcode} = params
|
||||
) do
|
||||
pack_dir = Path.join(@emoji_dir_path, pack_name)
|
||||
pack_dir = Path.join(emoji_dir_path(), pack_name)
|
||||
pack_file_p = Path.join(pack_dir, "pack.json")
|
||||
|
||||
full_pack = Jason.decode!(File.read!(pack_file_p))
|
||||
|
|
@ -513,11 +555,11 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
assumed to be emojis and stored in the new `pack.json` file.
|
||||
"""
|
||||
def import_from_fs(conn, _params) do
|
||||
with {:ok, results} <- File.ls(@emoji_dir_path) do
|
||||
with {:ok, results} <- File.ls(emoji_dir_path()) do
|
||||
imported_pack_names =
|
||||
results
|
||||
|> Enum.filter(fn file ->
|
||||
dir_path = Path.join(@emoji_dir_path, file)
|
||||
dir_path = Path.join(emoji_dir_path(), file)
|
||||
# Find the directories that do NOT have pack.json
|
||||
File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json"))
|
||||
end)
|
||||
|
|
@ -533,7 +575,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
end
|
||||
|
||||
defp write_pack_json_contents(dir) do
|
||||
dir_path = Path.join(@emoji_dir_path, dir)
|
||||
dir_path = Path.join(emoji_dir_path(), dir)
|
||||
emoji_txt_path = Path.join(dir_path, "emoji.txt")
|
||||
|
||||
files_for_pack = files_for_pack(emoji_txt_path, dir_path)
|
||||
|
|
@ -569,7 +611,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
# If there's no emoji.txt, assume all files
|
||||
# that are of certain extensions from the config are emojis and import them all
|
||||
pack_extensions = Pleroma.Config.get!([:emoji, :pack_extensions])
|
||||
Pleroma.Emoji.make_shortcode_to_file_map(dir_path, pack_extensions)
|
||||
Pleroma.Emoji.Loader.make_shortcode_to_file_map(dir_path, pack_extensions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ defmodule Pleroma.Web.Push.Subscription do
|
|||
@type t :: %__MODULE__{}
|
||||
|
||||
schema "push_subscriptions" do
|
||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||
belongs_to(:token, Token)
|
||||
field(:endpoint, :string)
|
||||
field(:key_p256dh, :string)
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ defmodule Pleroma.Web.Router do
|
|||
put("/:name", EmojiAPIController, :create)
|
||||
delete("/:name", EmojiAPIController, :delete)
|
||||
post("/download_from", EmojiAPIController, :download_from)
|
||||
post("/list_from", EmojiAPIController, :list_from)
|
||||
end
|
||||
|
||||
scope "/packs" do
|
||||
|
|
@ -324,11 +325,11 @@ defmodule Pleroma.Web.Router do
|
|||
get("/favourites", MastodonAPIController, :favourites)
|
||||
get("/bookmarks", MastodonAPIController, :bookmarks)
|
||||
|
||||
post("/notifications/clear", MastodonAPIController, :clear_notifications)
|
||||
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
|
||||
get("/notifications", MastodonAPIController, :notifications)
|
||||
get("/notifications/:id", MastodonAPIController, :get_notification)
|
||||
delete("/notifications/destroy_multiple", MastodonAPIController, :destroy_multiple)
|
||||
get("/notifications", NotificationController, :index)
|
||||
get("/notifications/:id", NotificationController, :show)
|
||||
post("/notifications/clear", NotificationController, :clear)
|
||||
post("/notifications/dismiss", NotificationController, :dismiss)
|
||||
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)
|
||||
|
||||
get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses)
|
||||
get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status)
|
||||
|
|
|
|||
|
|
@ -239,11 +239,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
|
||||
def emoji(conn, _params) do
|
||||
emoji =
|
||||
Emoji.get_all()
|
||||
|> Enum.map(fn {short_code, path, tags} ->
|
||||
{short_code, %{image_url: path, tags: tags}}
|
||||
Enum.reduce(Emoji.get_all(), %{}, fn {code, %Emoji{file: file, tags: tags}}, acc ->
|
||||
Map.put(acc, code, %{image_url: file, tags: tags})
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
json(conn, emoji)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Ecto.Changeset
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
|
|
@ -16,15 +15,12 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
action_fallback(:errors)
|
||||
|
||||
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
|
||||
with %User{} = user <- User.get_cached_by_id(uid),
|
||||
true <- user.local,
|
||||
true <- user.info.confirmation_pending,
|
||||
true <- user.info.confirmation_token == token,
|
||||
info_change <- User.Info.confirmation_changeset(user.info, need_confirmation: false),
|
||||
changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_change),
|
||||
{:ok, _} <- User.update_and_set_cache(changeset) do
|
||||
conn
|
||||
|> redirect(to: "/")
|
||||
new_info = [need_confirmation: false]
|
||||
|
||||
with %User{info: info} = user <- User.get_cached_by_id(uid),
|
||||
true <- user.local and info.confirmation_pending and info.confirmation_token == token,
|
||||
{:ok, _} <- User.update_info(user, &User.Info.confirmation_changeset(&1, new_info)) do
|
||||
redirect(conn, to: "/")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do
|
|||
field(:state, :string)
|
||||
field(:subscribers, {:array, :string}, default: [])
|
||||
field(:hub, :string)
|
||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue