diff options
author | kaniini <nenolod@gmail.com> | 2018-08-16 15:23:04 +0000 |
---|---|---|
committer | kaniini <nenolod@gmail.com> | 2018-08-16 15:23:04 +0000 |
commit | f2fa09c50fde8db4e619872ef6121e90a69324a6 (patch) | |
tree | 4d34037c5fc6d1a3c05a0b061f5279caef1bd671 /lib | |
parent | 718882b326f00c8315bca5acc439b92aa37bf021 (diff) | |
parent | 5fbb14f5ecbbd9feeed2a303c2619fbbba07d70e (diff) | |
download | pleroma-f2fa09c50fde8db4e619872ef6121e90a69324a6.tar.gz |
Merge branch 'develop' into 'patch-2'
# Conflicts:
# mix.exs
Diffstat (limited to 'lib')
33 files changed, 501 insertions, 126 deletions
diff --git a/lib/mix/tasks/generate_invite_token.ex b/lib/mix/tasks/generate_invite_token.ex new file mode 100644 index 000000000..c4daa9a6c --- /dev/null +++ b/lib/mix/tasks/generate_invite_token.ex @@ -0,0 +1,25 @@ +defmodule Mix.Tasks.GenerateInviteToken do + use Mix.Task + + @shortdoc "Generate invite token for user" + def run([]) do + Mix.Task.run("app.start") + + with {:ok, token} <- Pleroma.UserInviteToken.create_token() do + IO.puts("Generated user invite token") + + IO.puts( + "Url: #{ + Pleroma.Web.Router.Helpers.redirect_url( + Pleroma.Web.Endpoint, + :registration_page, + token.token + ) + }" + ) + else + _ -> + IO.puts("Error creating token") + end + end +end diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index dd6805125..bed96861f 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -78,4 +78,8 @@ defmodule Pleroma.Activity do end def get_create_activity_by_object_ap_id(_), do: nil + + def normalize(obj) when is_map(obj), do: Activity.get_by_ap_id(obj["id"]) + def normalize(ap_id) when is_binary(ap_id), do: Activity.get_by_ap_id(ap_id) + def normalize(_), do: nil end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index df7ffbc41..d199c9243 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -116,7 +116,28 @@ defmodule Pleroma.Formatter do _ -> [] end) - @emoji @finmoji_with_filenames ++ @emoji_from_file + @emoji_from_globs ( + static_path = Path.join(:code.priv_dir(:pleroma), "static") + + globs = + Application.get_env(:pleroma, :emoji, []) + |> Keyword.get(:shortcode_globs, []) + + paths = + Enum.map(globs, fn glob -> + Path.join(static_path, glob) + |> Path.wildcard() + end) + |> Enum.concat() + + Enum.map(paths, fn path -> + shortcode = Path.basename(path, Path.extname(path)) + external_path = Path.join("/", Path.relative_to(path, static_path)) + {shortcode, external_path} + end) + ) + + @emoji @finmoji_with_filenames ++ @emoji_from_globs ++ @emoji_from_file def emojify(text, emoji \\ @emoji) def emojify(text, nil), do: text @@ -223,8 +244,8 @@ defmodule Pleroma.Formatter do subs = subs ++ - Enum.map(tags, fn {_, tag, uuid} -> - url = "<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>##{tag}</a>" + Enum.map(tags, fn {tag_text, tag, uuid} -> + url = "<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{tag_text}</a>" {uuid, url} end) diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index f6abcd4d0..97a1dea77 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -54,7 +54,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do String.split(text, "\r") |> Enum.map(fn text -> - "i#{text}\tfake\(NULL)\t0\r\n" + "i#{text}\tfake\t(NULL)\t0\r\n" end) |> Enum.join("") end @@ -77,14 +77,14 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do link("Post ##{activity.id} by #{user.nickname}", "/notices/#{activity.id}") <> info("#{like_count} likes, #{announcement_count} repeats") <> - "\r\n" <> + "i\tfake\t(NULL)\t0\r\n" <> info( HtmlSanitizeEx.strip_tags( String.replace(activity.data["object"]["content"], "<br>", "\r") ) ) end) - |> Enum.join("\r\n") + |> Enum.join("i\tfake\t(NULL)\t0\r\n") end def response("") do diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index ff2af4a6f..1bcff5a7b 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -27,6 +27,10 @@ defmodule Pleroma.Object do Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id))) end + def normalize(obj) when is_map(obj), do: Object.get_by_ap_id(obj["id"]) + def normalize(ap_id) when is_binary(ap_id), do: Object.get_by_ap_id(ap_id) + def normalize(_), do: nil + def get_cached_by_ap_id(ap_id) do if Mix.env() == :test do get_by_ap_id(ap_id) diff --git a/lib/pleroma/plugs/digest.ex b/lib/pleroma/plugs/digest.ex new file mode 100644 index 000000000..9d6bbb085 --- /dev/null +++ b/lib/pleroma/plugs/digest.ex @@ -0,0 +1,10 @@ +defmodule Pleroma.Web.Plugs.DigestPlug do + alias Plug.Conn + require Logger + + def read_body(conn, opts) do + {:ok, body, conn} = Conn.read_body(conn, opts) + digest = "SHA-256=" <> (:crypto.hash(:sha256, body) |> Base.encode64()) + {:ok, body, Conn.assign(conn, :digest, digest)} + end +end diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index 38bcd3a78..9e53371b7 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -19,6 +19,8 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do cond do signature && String.contains?(signature, user) -> + # set (request-target) header to the appropriate value + # we also replace the digest header with the one we computed conn = conn |> put_req_header( @@ -26,6 +28,14 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do String.downcase("#{conn.method}") <> " #{conn.request_path}" ) + conn = + if conn.assigns[:digest] do + conn + |> put_req_header("digest", conn.assigns[:digest]) + else + conn + end + assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) signature -> diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 43df0d418..e0cb545b0 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -18,8 +18,10 @@ defmodule Pleroma.Upload do File.cp!(file.path, result_file) end + strip_exif_data(content_type, result_file) + %{ - "type" => "Image", + "type" => "Document", "url" => [ %{ "type" => "Link", @@ -67,6 +69,8 @@ defmodule Pleroma.Upload do File.rename(uuidpath, result_file) end + strip_exif_data(content_type, result_file) + %{ "type" => "Image", "url" => [ @@ -80,6 +84,16 @@ defmodule Pleroma.Upload do } end + def strip_exif_data(content_type, file) do + settings = Application.get_env(:pleroma, Pleroma.Upload) + do_strip = Keyword.fetch!(settings, :strip_exif) + [filetype, ext] = String.split(content_type, "/") + + if filetype == "image" and do_strip == true do + Mogrify.open(file) |> Mogrify.custom("strip") |> Mogrify.save(in_place: true) + end + end + def upload_path do settings = Application.get_env(:pleroma, Pleroma.Upload) Keyword.fetch!(settings, :uploads) @@ -110,20 +124,20 @@ defmodule Pleroma.Upload do if should_dedupe do create_name(uuid, List.last(String.split(file.filename, ".")), type) else - unless String.contains?(file.filename, ".") do - case type do - "image/png" -> file.filename <> ".png" - "image/jpeg" -> file.filename <> ".jpg" - "image/gif" -> file.filename <> ".gif" - "video/webm" -> file.filename <> ".webm" - "video/mp4" -> file.filename <> ".mp4" - "audio/mpeg" -> file.filename <> ".mp3" - "audio/ogg" -> file.filename <> ".ogg" - "audio/wav" -> file.filename <> ".wav" - _ -> file.filename + parts = String.split(file.filename, ".") + + new_filename = + if length(parts) > 1 do + Enum.drop(parts, -1) |> Enum.join(".") + else + Enum.join(parts) end - else - file.filename + + case type do + "application/octet-stream" -> file.filename + "audio/mpeg" -> new_filename <> ".mp3" + "image/jpeg" -> new_filename <> ".jpg" + _ -> Enum.join([new_filename, String.split(type, "/") |> List.last()], ".") end end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 94f16c3c0..fa0ea171d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -398,6 +398,7 @@ defmodule Pleroma.User do Enum.map(reqs, fn req -> req.actor end) |> Enum.uniq() |> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end) + |> Enum.filter(fn u -> !following?(u, user) end) {:ok, users} end @@ -607,7 +608,7 @@ defmodule Pleroma.User do |> Enum.each(fn activity -> case activity.data["type"] do "Create" -> - ActivityPub.delete(Object.get_by_ap_id(activity.data["object"]["id"])) + ActivityPub.delete(Object.normalize(activity.data["object"])) # TODO: Do something with likes, follows, repeats. _ -> diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex new file mode 100644 index 000000000..48ee1019a --- /dev/null +++ b/lib/pleroma/user_invite_token.ex @@ -0,0 +1,40 @@ +defmodule Pleroma.UserInviteToken do + use Ecto.Schema + + import Ecto.Changeset + + alias Pleroma.{User, UserInviteToken, Repo} + + schema "user_invite_tokens" do + field(:token, :string) + field(:used, :boolean, default: false) + + timestamps() + end + + def create_token do + token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() + + token = %UserInviteToken{ + used: false, + token: token + } + + Repo.insert(token) + end + + def used_changeset(struct) do + struct + |> cast(%{}, []) + |> put_change(:used, true) + end + + def mark_as_used(token) do + with %{used: false} = token <- Repo.get_by(UserInviteToken, %{token: token}), + {:ok, token} <- Repo.update(used_changeset(token)) do + {:ok, token} + else + _e -> {:error, token} + end + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 195679fad..ec605b694 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -30,7 +30,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def insert(map, local \\ true) when is_map(map) do - with nil <- Activity.get_by_ap_id(map["id"]), + with nil <- Activity.normalize(map), map <- lazy_put_activity_defaults(map), :ok <- check_actor_is_active(map["actor"]), {:ok, map} <- MRF.filter(map), @@ -641,13 +641,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Logger.info("Federating #{id} to #{inbox}") host = URI.parse(inbox).host + digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) + signature = - Pleroma.Web.HTTPSignatures.sign(actor, %{host: host, "content-length": byte_size(json)}) + Pleroma.Web.HTTPSignatures.sign(actor, %{ + host: host, + "content-length": byte_size(json), + digest: digest + }) @httpoison.post( inbox, json, - [{"Content-Type", "application/activity+json"}, {"signature", signature}], + [ + {"Content-Type", "application/activity+json"}, + {"signature", signature}, + {"digest", digest} + ], hackney: [pool: :default] ) end @@ -670,7 +680,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do recv_timeout: 20000 ), {:ok, data} <- Jason.decode(body), - nil <- Object.get_by_ap_id(data["id"]), + nil <- Object.normalize(data), params <- %{ "type" => "Create", "to" => data["to"], @@ -679,7 +689,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "object" => data }, {:ok, activity} <- Transmogrifier.handle_incoming(params) do - {:ok, Object.get_by_ap_id(activity.data["object"]["id"])} + {:ok, Object.normalize(activity.data["object"])} else object = %Object{} -> {:ok, object} @@ -688,7 +698,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Logger.info("Couldn't get object via AP, trying out OStatus fetching...") case OStatus.fetch_activity_from_url(id) do - {:ok, [activity | _]} -> {:ok, Object.get_by_ap_id(activity.data["object"]["id"])} + {:ok, [activity | _]} -> {:ok, Object.normalize(activity.data["object"])} e -> e end end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 30cd70fb6..e5fb6e033 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -13,18 +13,58 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do require Logger + def get_actor(%{"actor" => actor}) when is_binary(actor) do + actor + end + + def get_actor(%{"actor" => actor}) when is_list(actor) do + Enum.at(actor, 0) + end + + def get_actor(%{"actor" => actor}) when is_map(actor) do + actor["id"] + end + + def get_actor(%{"actor" => actor_list}) do + Enum.find(actor_list, fn %{"type" => type} -> type == "Person" end) + |> Map.get("id") + end + @doc """ Modifies an incoming AP object (mastodon format) to our internal format. """ def fix_object(object) do object - |> Map.put("actor", object["attributedTo"]) + |> fix_actor |> fix_attachments |> fix_context |> fix_in_reply_to |> fix_emoji |> fix_tag |> fix_content_map + |> fix_addressing + end + + def fix_addressing_list(map, field) do + if is_binary(map[field]) do + map + |> Map.put(field, [map[field]]) + else + map + end + end + + def fix_addressing(map) do + map + |> fix_addressing_list("to") + |> fix_addressing_list("cc") + |> fix_addressing_list("bto") + |> fix_addressing_list("bcc") + end + + def fix_actor(%{"attributedTo" => actor} = object) do + object + |> Map.put("actor", get_actor(%{"actor" => actor})) end def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object) @@ -122,7 +162,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # TODO: validate those with a Ecto scheme # - tags # - emoji - def handle_incoming(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do + def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data) + when objtype in ["Article", "Note"] do + actor = get_actor(data) + + data = + Map.put(data, "actor", actor) + |> fix_addressing + with nil <- Activity.get_create_activity_by_object_ap_id(object["id"]), %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do object = fix_object(data["object"]) @@ -412,7 +459,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def handle_incoming(_), do: :error def get_obj_helper(id) do - if object = Object.get_by_ap_id(id), do: {:ok, object}, else: nil + if object = Object.normalize(id), do: {:ok, object}, else: nil end def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) do @@ -460,14 +507,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # Mastodon Accept/Reject requires a non-normalized object containing the actor URIs, # because of course it does. def prepare_outgoing(%{"type" => "Accept"} = data) do - follow_activity_id = - if is_binary(data["object"]) do - data["object"] - else - data["object"]["id"] - end - - with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do + with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, "object" => follow_activity.data["object"], @@ -485,14 +525,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def prepare_outgoing(%{"type" => "Reject"} = data) do - follow_activity_id = - if is_binary(data["object"]) do - data["object"] - else - data["object"]["id"] - end - - with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do + with follow_activity <- Activity.normalize(data["object"]) do object = %{ "actor" => follow_activity.actor, "object" => follow_activity.data["object"], diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 64329b710..8b41a3bec 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -128,7 +128,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do Inserts a full object if it is contained in an activity. """ def insert_full_object(%{"object" => %{"type" => type} = object_data}) - when is_map(object_data) and type in ["Note"] do + when is_map(object_data) and type in ["Article", "Note"] do with {:ok, _} <- Object.create(object_data) do :ok end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index f4b2e0610..0b1d5a9fa 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do def render("user.json", %{user: user}) do {:ok, user} = WebFinger.ensure_keys_present(user) {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"]) - public_key = :public_key.pem_entry_encode(:RSAPublicKey, public_key) + public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) %{ @@ -98,9 +98,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do info = User.user_info(user) params = %{ - "type" => ["Create", "Announce"], - "actor_id" => user.ap_id, - "whole_db" => true, "limit" => "10" } @@ -111,10 +108,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do params end - activities = ActivityPub.fetch_public_activities(params) - min_id = Enum.at(activities, 0).id - - activities = Enum.reverse(activities) + activities = ActivityPub.fetch_user_activities(user, nil, params) + min_id = Enum.at(Enum.reverse(activities), 0).id max_id = Enum.at(activities, 0).id collection = diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 8845419c2..3f18a68e8 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.CommonAPI do def delete(activity_id, user) do with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id), - %Object{} = object <- Object.get_by_ap_id(object_id), + %Object{} = object <- Object.normalize(object_id), true <- user.info["is_moderator"] || user.ap_id == object.data["actor"], {:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} @@ -16,7 +16,7 @@ defmodule Pleroma.Web.CommonAPI do def repeat(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - object <- Object.get_by_ap_id(activity.data["object"]["id"]) do + object <- Object.normalize(activity.data["object"]["id"]) do ActivityPub.announce(user, object) else _ -> @@ -26,7 +26,7 @@ defmodule Pleroma.Web.CommonAPI do def unrepeat(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), - object <- Object.get_by_ap_id(activity.data["object"]["id"]) do + object <- Object.normalize(activity.data["object"]["id"]) do ActivityPub.unannounce(user, object) else _ -> @@ -37,7 +37,7 @@ defmodule Pleroma.Web.CommonAPI do def favorite(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), false <- activity.data["actor"] == user.ap_id, - object <- Object.get_by_ap_id(activity.data["object"]["id"]) do + object <- Object.normalize(activity.data["object"]["id"]) do ActivityPub.like(user, object) else _ -> @@ -48,7 +48,7 @@ defmodule Pleroma.Web.CommonAPI do def unfavorite(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), false <- activity.data["actor"] == user.ap_id, - object <- Object.get_by_ap_id(activity.data["object"]["id"]) do + object <- Object.normalize(activity.data["object"]["id"]) do ActivityPub.unlike(user, object) else _ -> diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 1a012c1b4..cbedca004 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -35,7 +35,8 @@ defmodule Pleroma.Web.Endpoint do parsers: [:urlencoded, :multipart, :json], pass: ["*/*"], json_decoder: Jason, - length: Application.get_env(:pleroma, :instance) |> Keyword.get(:upload_limit) + length: Application.get_env(:pleroma, :instance) |> Keyword.get(:upload_limit), + body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} ) plug(Plug.MethodOverride) diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 8ca530031..ccefb0bdf 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -95,7 +95,7 @@ defmodule Pleroma.Web.Federator do params = Utils.normalize_params(params) with {:ok, _user} <- ap_enabled_actor(params["actor"]), - nil <- Activity.get_by_ap_id(params["id"]), + nil <- Activity.normalize(params["id"]), {:ok, _activity} <- Transmogrifier.handle_incoming(params) do else %Activity{} -> diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 9d3f526c9..cd9525252 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1,6 +1,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller - alias Pleroma.{Repo, Activity, User, Notification, Stats} + alias Pleroma.{Repo, Object, Activity, User, Notification, Stats} alias Pleroma.Web alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView} alias Pleroma.Web.ActivityPub.ActivityPub @@ -11,6 +11,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do import Ecto.Query require Logger + @httpoison Application.get_env(:pleroma, :httpoison) + action_fallback(:errors) def create_app(conn, params) do @@ -125,7 +127,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do response = %{ uri: Web.base_url(), title: Keyword.get(@instance, :name), - description: "A Pleroma instance, an alternative fediverse server", + description: Keyword.get(@instance, :description), version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})", email: Keyword.get(@instance, :email), urls: %{ @@ -428,16 +430,43 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do render(conn, AccountView, "relationships.json", %{user: user, targets: targets}) end - def upload(%{assigns: %{user: _}} = conn, %{"file" => file}) do - with {:ok, object} <- ActivityPub.upload(file) do + def update_media(%{assigns: %{user: _}} = conn, data) do + with %Object{} = object <- Repo.get(Object, data["id"]), + true <- is_binary(data["description"]), + description <- data["description"] do + new_data = %{object.data | "name" => description} + + change = Object.change(object, %{data: new_data}) + {:ok, media_obj} = Repo.update(change) + data = - object.data + new_data |> Map.put("id", object.id) render(conn, StatusView, "attachment.json", %{attachment: data}) end end + def upload(%{assigns: %{user: _}} = conn, %{"file" => file} = data) do + with {:ok, object} <- ActivityPub.upload(file) do + objdata = + if Map.has_key?(data, "description") do + Map.put(object.data, "name", data["description"]) + else + object.data + end + + change = Object.change(object, %{data: objdata}) + {:ok, object} = Repo.update(change) + + objdata = + objdata + |> Map.put("id", object.id) + + render(conn, StatusView, "attachment.json", %{attachment: objdata}) + end + end + def favourited_by(conn, %{"id" => id}) do with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do q = from(u in User, where: u.ap_id in ^likes) @@ -873,7 +902,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do }, compose: %{ me: "#{user.id}", - default_privacy: "public", + default_privacy: user.info["default_scope"] || "public", default_sensitive: false }, media_attachments: %{ @@ -1070,4 +1099,38 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> put_status(500) |> json("Something went wrong") end + + @suggestions Application.get_env(:pleroma, :suggestions) + + def suggestions(%{assigns: %{user: user}} = conn, _) do + if Keyword.get(@suggestions, :enabled, false) do + api = Keyword.get(@suggestions, :third_party_engine, "") + timeout = Keyword.get(@suggestions, :timeout, 5000) + + host = + Application.get_env(:pleroma, Pleroma.Web.Endpoint) + |> Keyword.get(:url) + |> Keyword.get(:host) + + user = user.nickname + url = String.replace(api, "{{host}}", host) |> String.replace("{{user}}", user) + + with {:ok, %{status_code: 200, body: body}} <- + @httpoison.get(url, [], timeout: timeout, recv_timeout: timeout), + {:ok, data} <- Jason.decode(body) do + data2 = + Enum.slice(data, 0, 40) + |> Enum.map(fn x -> + Map.put(x, "id", User.get_or_fetch(x["acct"]).id) + end) + + conn + |> json(data2) + else + e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") + end + else + json(conn, []) + end + end end diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index f33d615cf..cc5261616 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -14,6 +14,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do header = User.banner_url(user) |> MediaProxy.url() user_info = User.user_info(user) + emojis = + (user.info["source_data"]["tag"] || []) + |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) + |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> + %{ + "shortcode" => String.trim(name, ":"), + "url" => MediaProxy.url(url), + "static_url" => MediaProxy.url(url), + "visible_in_picker" => false + } + end) + %{ id: to_string(user.id), username: hd(String.split(user.nickname, "@")), @@ -30,7 +42,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do avatar_static: image, header: header, header_static: header, - emojis: [], + emojis: emojis, fields: [], source: %{ note: "", diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 59898457b..5dbd59dd9 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -54,8 +54,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do %{ id: to_string(activity.id), uri: object, - # TODO: This might be wrong, check with mastodon. - url: nil, + url: object, account: AccountView.render("account.json", %{user: user}), in_reply_to_id: nil, in_reply_to_account_id: nil, @@ -128,7 +127,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do in_reply_to_id: reply_to && to_string(reply_to.id), in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id), reblog: nil, - content: HtmlSanitizeEx.basic_html(object["content"]), + content: render_content(object), created_at: created_at, reblogs_count: announcement_count, favourites_count: like_count, @@ -170,7 +169,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do remote_url: href, preview_url: MediaProxy.url(href), text_url: href, - type: type + type: type, + description: attachment["name"] } end @@ -207,4 +207,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do "direct" end end + + def render_content(%{"type" => "Article"} = object) do + summary = object["name"] + + content = + if !!summary and summary != "" do + "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}" + else + object["content"] + end + + HtmlSanitizeEx.basic_html(content) + end + + def render_content(object) do + HtmlSanitizeEx.basic_html(object["content"]) + end end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index aec77168a..2fab60274 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -4,8 +4,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do alias Pleroma.Stats alias Pleroma.Web - @instance Application.get_env(:pleroma, :instance) - def schemas(conn, _params) do response = %{ links: [ @@ -21,20 +19,23 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do # Schema definition: https://github.com/jhass/nodeinfo/blob/master/schemas/2.0/schema.json def nodeinfo(conn, %{"version" => "2.0"}) do + instance = Application.get_env(:pleroma, :instance) + media_proxy = Application.get_env(:pleroma, :media_proxy) + suggestions = Application.get_env(:pleroma, :suggestions) stats = Stats.get_stats() response = %{ version: "2.0", software: %{ name: "pleroma", - version: Keyword.get(@instance, :version) + version: Keyword.get(instance, :version) }, protocols: ["ostatus", "activitypub"], services: %{ inbound: [], outbound: [] }, - openRegistrations: Keyword.get(@instance, :registrations_open), + openRegistrations: Keyword.get(instance, :registrations_open), usage: %{ users: %{ total: stats.user_count || 0 @@ -42,7 +43,16 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do localPosts: stats.status_count || 0 }, metadata: %{ - nodeName: Keyword.get(@instance, :name) + nodeName: Keyword.get(instance, :name), + nodeDescription: Keyword.get(instance, :description), + mediaProxy: Keyword.get(media_proxy, :enabled), + private: !Keyword.get(instance, :public, true), + suggestions: %{ + enabled: Keyword.get(suggestions, :enabled, false), + thirdPartyEngine: Keyword.get(suggestions, :third_party_engine, ""), + timeout: Keyword.get(suggestions, :timeout, 5000), + web: Keyword.get(suggestions, :web, "") + } } } diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 4179d86c9..5d831459b 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -246,7 +246,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] mentions = (activity.recipients || []) |> get_mentions - follow_activity = Activity.get_by_ap_id(follow_activity["id"]) + follow_activity = Activity.normalize(follow_activity) [ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']}, diff --git a/lib/pleroma/web/ostatus/handlers/delete_handler.ex b/lib/pleroma/web/ostatus/handlers/delete_handler.ex index 4f3016b65..6330d7f64 100644 --- a/lib/pleroma/web/ostatus/handlers/delete_handler.ex +++ b/lib/pleroma/web/ostatus/handlers/delete_handler.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.OStatus.DeleteHandler do def handle_delete(entry, _doc \\ nil) do with id <- XML.string_from_xpath("//id", entry), - object when not is_nil(object) <- Object.get_by_ap_id(id), + %Object{} = object <- Object.normalize(id), {:ok, delete} <- ActivityPub.delete(object, false) do delete end diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index f0ff0624f..916c894eb 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -89,7 +89,7 @@ defmodule Pleroma.Web.OStatus do def make_share(entry, doc, retweeted_activity) do with {:ok, actor} <- find_make_or_update_user(doc), - %Object{} = object <- Object.get_by_ap_id(retweeted_activity.data["object"]["id"]), + %Object{} = object <- Object.normalize(retweeted_activity.data["object"]), id when not is_nil(id) <- string_from_xpath("/entry/id", entry), {:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do {:ok, activity} @@ -107,7 +107,7 @@ defmodule Pleroma.Web.OStatus do def make_favorite(entry, doc, favorited_activity) do with {:ok, actor} <- find_make_or_update_user(doc), - %Object{} = object <- Object.get_by_ap_id(favorited_activity.data["object"]["id"]), + %Object{} = object <- Object.normalize(favorited_activity.data["object"]), id when not is_nil(id) <- string_from_xpath("/entry/id", entry), {:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do {:ok, activity} diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 2f72fdb16..09d1b1110 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Repo alias Pleroma.Web.{OStatus, Federator} alias Pleroma.Web.XML + alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ActivityPub @@ -90,7 +91,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do case get_format(conn) do "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, activity, user) + _ -> represent_activity(conn, nil, activity, user) end else {:public?, false} -> @@ -107,12 +108,12 @@ defmodule Pleroma.Web.OStatus.OStatusController do def activity(conn, %{"uuid" => uuid}) do with id <- o_status_url(conn, :activity, uuid), - {_, %Activity{} = activity} <- {:activity, Activity.get_by_ap_id(id)}, + {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, true} <- {:public?, ActivityPub.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - case get_format(conn) do + case format = get_format(conn) do "html" -> redirect(conn, to: "/notice/#{activity.id}") - _ -> represent_activity(conn, activity, user) + _ -> represent_activity(conn, format, activity, user) end else {:public?, false} -> @@ -130,14 +131,14 @@ defmodule Pleroma.Web.OStatus.OStatusController do with {_, %Activity{} = activity} <- {:activity, Repo.get(Activity, id)}, {_, true} <- {:public?, ActivityPub.is_public?(activity)}, %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do - case get_format(conn) do + case format = get_format(conn) do "html" -> conn |> put_resp_content_type("text/html") |> send_file(200, "priv/static/index.html") _ -> - represent_activity(conn, activity, user) + represent_activity(conn, format, activity, user) end else {:public?, false} -> @@ -151,7 +152,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do end end - defp represent_activity(conn, activity, user) do + defp represent_activity(conn, "activity+json", activity, user) do + conn + |> put_resp_header("content-type", "application/activity+json") + |> json(ObjectView.render("object.json", %{object: activity})) + end + + defp represent_activity(conn, _, activity, user) do response = activity |> ActivityRepresenter.to_simple_form(user, true) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 34652cdde..2dadf974c 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -127,6 +127,7 @@ defmodule Pleroma.Web.Router do get("/notifications/:id", MastodonAPIController, :get_notification) post("/media", MastodonAPIController, :upload) + put("/media/:id", MastodonAPIController, :update_media) get("/lists", MastodonAPIController, :get_lists) get("/lists/:id", MastodonAPIController, :get_list) @@ -140,6 +141,8 @@ defmodule Pleroma.Web.Router do get("/domain_blocks", MastodonAPIController, :domain_blocks) post("/domain_blocks", MastodonAPIController, :block_domain) delete("/domain_blocks", MastodonAPIController, :unblock_domain) + + get("/suggestions", MastodonAPIController, :suggestions) end scope "/api/web", Pleroma.Web.MastodonAPI do @@ -201,9 +204,7 @@ defmodule Pleroma.Web.Router do get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status) get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation) - if @registrations_open do - post("/account/register", TwitterAPI.Controller, :register) - end + post("/account/register", TwitterAPI.Controller, :register) get("/search", TwitterAPI.Controller, :search) get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline) @@ -355,6 +356,7 @@ defmodule Pleroma.Web.Router do end scope "/", Fallback do + get("/registration/:token", RedirectController, :registration_page) get("/*path", RedirectController, :redirector) end end @@ -369,4 +371,8 @@ defmodule Fallback.RedirectController do |> send_file(200, "priv/static/index.html") end end + + def registration_page(conn, params) do + redirector(conn, params) + end end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index ce38f3cc3..c61bad830 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -158,7 +158,7 @@ defmodule Pleroma.Web.Streamer do user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) blocks = user.info["blocks"] || [] - parent = Object.get_by_ap_id(item.data["object"]) + parent = Object.normalize(item.data["object"]) unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do send(socket.transport_pid, {:text, represent_update(item, user)}) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 7a0c37ce9..24ebdf007 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -99,6 +99,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do conn |> render("followed.html", %{error: false}) else + # Was already following user + {:error, "Could not follow user:" <> _rest} -> + render(conn, "followed.html", %{error: false}) + _e -> conn |> render("follow_login.html", %{ @@ -117,6 +121,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do conn |> render("followed.html", %{error: false}) else + # Was already following user + {:error, "Could not follow user:" <> _rest} -> + conn + |> render("followed.html", %{error: false}) + e -> Logger.debug("Remote follow failed with error #{inspect(e)}") @@ -126,6 +135,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end @instance Application.get_env(:pleroma, :instance) + @instance_fe Application.get_env(:pleroma, :fe) + @instance_chat Application.get_env(:pleroma, :chat) def config(conn, _params) do case get_format(conn) do "xml" -> @@ -148,9 +159,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do json(conn, %{ site: %{ name: Keyword.get(@instance, :name), + description: Keyword.get(@instance, :description), server: Web.base_url(), textlimit: to_string(Keyword.get(@instance, :limit)), - closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1") + closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"), + private: if(Keyword.get(@instance, :public, true), do: "0", else: "1"), + pleromafe: %{ + theme: Keyword.get(@instance_fe, :theme), + background: Keyword.get(@instance_fe, :background), + logo: Keyword.get(@instance_fe, :logo), + redirectRootNoLogin: Keyword.get(@instance_fe, :redirect_root_no_login), + redirectRootLogin: Keyword.get(@instance_fe, :redirect_root_login), + chatDisabled: !Keyword.get(@instance_chat, :enabled), + showInstanceSpecificPanel: Keyword.get(@instance_fe, :show_instance_panel), + showWhoToFollowPanel: Keyword.get(@instance_fe, :show_who_to_follow_panel), + scopeOptionsEnabled: Keyword.get(@instance_fe, :scope_options_enabled), + whoToFollowProvider: Keyword.get(@instance_fe, :who_to_follow_provider), + whoToFollowLink: Keyword.get(@instance_fe, :who_to_follow_link) + } } }) end diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex index 57837205e..26bfb79af 100644 --- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter alias Pleroma.{Activity, User} - alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView} + alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView} alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Formatter @@ -164,14 +164,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags - summary = activity.data["object"]["summary"] - - content = - if !!summary and summary != "" do - "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>" - else - content - end + {summary, content} = ActivityView.render_content(object) html = HtmlSanitizeEx.basic_html(content) @@ -198,7 +191,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do "tags" => tags, "activity_type" => "post", "possibly_sensitive" => possibly_sensitive, - "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object) + "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object), + "summary" => object["summary"] } end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index c23b3c2c4..dbad08e66 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -1,11 +1,13 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do - alias Pleroma.{User, Activity, Repo, Object} + alias Pleroma.{UserInviteToken, User, Activity, Repo, Object} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.TwitterAPI.UserView alias Pleroma.Web.{OStatus, CommonAPI} import Ecto.Query + @instance Application.get_env(:pleroma, :instance) @httpoison Application.get_env(:pleroma, :httpoison) + @registrations_open Keyword.get(@instance, :registrations_open) def create_status(%User{} = user, %{"status" => _} = data) do CommonAPI.post(user, data) @@ -120,6 +122,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def register_user(params) do + tokenString = params["token"] + params = %{ nickname: params["nickname"], name: params["fullname"], @@ -129,17 +133,33 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do password_confirmation: params["confirm"] } - changeset = User.register_changeset(%User{}, params) + # no need to query DB if registration is open + token = + unless @registrations_open || is_nil(tokenString) do + Repo.get_by(UserInviteToken, %{token: tokenString}) + end - with {:ok, user} <- Repo.insert(changeset) do - {:ok, user} - else - {:error, changeset} -> - errors = - Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) - |> Jason.encode!() + cond do + @registrations_open || (!is_nil(token) && !token.used) -> + changeset = User.register_changeset(%User{}, params) + + with {:ok, user} <- Repo.insert(changeset) do + !@registrations_open && UserInviteToken.mark_as_used(token.token) + {:ok, user} + else + {:error, changeset} -> + errors = + Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end) + |> Jason.encode!() + + {:error, %{error: errors}} + end + + !@registrations_open && is_nil(token) -> + {:error, "Invalid token"} - {:error, %{error: errors}} + !@registrations_open && token.used -> + {:error, "Expired token"} end end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 8f5b3c786..65e67396b 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -431,6 +431,19 @@ defmodule Pleroma.Web.TwitterAPI.Controller do user end + user = + if default_scope = params["default_scope"] do + with new_info <- Map.put(user.info, "default_scope", default_scope), + change <- User.info_changeset(user, %{info: new_info}), + {:ok, user} <- User.update_and_set_cache(change) do + user + else + _e -> user + end + else + user + end + with changeset <- User.update_changeset(user, params), {:ok, user} <- User.update_and_set_cache(changeset) do CommonAPI.update(user) diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 62ce3b7b5..55b5287f5 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -228,15 +228,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags - summary = activity.data["object"]["summary"] - content = object["content"] - - content = - if !!summary and summary != "" do - "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>" - else - content - end + {summary, content} = render_content(object) html = HtmlSanitizeEx.basic_html(content) @@ -263,7 +255,41 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "tags" => tags, "activity_type" => "post", "possibly_sensitive" => possibly_sensitive, - "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object) + "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object), + "summary" => summary } end + + def render_content(%{"type" => "Note"} = object) do + summary = object["summary"] + + content = + if !!summary and summary != "" do + "<p>#{summary}</p>#{object["content"]}" + else + object["content"] + end + + {summary, content} + end + + def render_content(%{"type" => "Article"} = object) do + summary = object["name"] || object["summary"] + + content = + if !!summary and summary != "" do + "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}" + else + object["content"] + end + + {summary, content} + end + + def render_content(object) do + summary = object["summary"] || "Unhandled activity type: #{object["type"]}" + content = "<p>#{summary}</p>#{object["content"]}" + + {summary, content} + end end diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 711008973..7d0f0e703 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -1,6 +1,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do use Pleroma.Web, :view alias Pleroma.User + alias Pleroma.Formatter alias Pleroma.Web.CommonAPI.Utils alias Pleroma.Web.MediaProxy @@ -28,9 +29,19 @@ defmodule Pleroma.Web.TwitterAPI.UserView do user_info = User.get_cached_user_info(user) + emoji = + (user.info["source_data"]["tag"] || []) + |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) + |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> + {String.trim(name, ":"), url} + end) + + bio = HtmlSanitizeEx.strip_tags(user.bio) + data = %{ "created_at" => user.inserted_at |> Utils.format_naive_asctime(), - "description" => HtmlSanitizeEx.strip_tags(user.bio), + "description" => bio, + "description_html" => bio |> Formatter.emojify(emoji), "favourites_count" => 0, "followers_count" => user_info[:follower_count], "following" => following, @@ -39,6 +50,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do "friends_count" => user_info[:following_count], "id" => user.id, "name" => user.name, + "name_html" => HtmlSanitizeEx.strip_tags(user.name) |> Formatter.emojify(emoji), "profile_image_url" => image, "profile_image_url_https" => image, "profile_image_url_profile_size" => image, @@ -52,7 +64,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do "cover_photo" => User.banner_url(user) |> MediaProxy.url(), "background_image" => image_url(user.info["background"]) |> MediaProxy.url(), "is_local" => user.local, - "locked" => !!user.info["locked"] + "locked" => !!user.info["locked"], + "default_scope" => user.info["default_scope"] || "public" } if assigns[:token] do |