Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85710103
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index 4afc73bf4..66ca92f27 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -1,204 +1,200 @@
defmodule Pleroma.Formatter do
alias Pleroma.User
alias Pleroma.Web.MediaProxy
@tag_regex ~r/\#\w+/u
def parse_tags(text, data \\ %{}) do
Regex.scan(@tag_regex, text)
|> Enum.map(fn (["#" <> tag = full_tag]) -> {full_tag, String.downcase(tag)} end)
|> (fn map -> if data["sensitive"] in [true, "True", "true", "1"], do: [{"#nsfw", "nsfw"}] ++ map, else: map end).()
end
def parse_mentions(text) do
# Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
regex = ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/u
Regex.scan(regex, text)
|> List.flatten
|> Enum.uniq
|> Enum.map(fn ("@" <> match = full_match) -> {full_match, User.get_cached_by_nickname(match)} end)
|> Enum.filter(fn ({_match, user}) -> user end)
end
@finmoji [
"a_trusted_friend",
"alandislands",
"association",
"auroraborealis",
"baby_in_a_box",
"bear",
"black_gold",
"christmasparty",
"crosscountryskiing",
"cupofcoffee",
"education",
"fashionista_finns",
"finnishlove",
"flag",
"forest",
"four_seasons_of_bbq",
"girlpower",
"handshake",
"happiness",
"headbanger",
"icebreaker",
"iceman",
"joulutorttu",
"kaamos",
"kalsarikannit_f",
"kalsarikannit_m",
"karjalanpiirakka",
"kicksled",
"kokko",
"lavatanssit",
"losthopes_f",
"losthopes_m",
"mattinykanen",
"meanwhileinfinland",
"moominmamma",
"nordicfamily",
"out_of_office",
"peacemaker",
"perkele",
"pesapallo",
"polarbear",
"pusa_hispida_saimensis",
"reindeer",
"sami",
"sauna_f",
"sauna_m",
"sauna_whisk",
"sisu",
"stuck",
"suomimainittu",
"superfood",
"swan",
"the_cap",
"the_conductor",
"the_king",
"the_voice",
"theoriginalsanta",
"tomoffinland",
"torillatavataan",
"unbreakable",
"waiting",
"white_nights",
"woollysocks"
]
@finmoji_with_filenames Enum.map(@finmoji, fn (finmoji) ->
{finmoji, "/finmoji/128px/#{finmoji}-128.png"}
end)
@emoji_from_file (with {:ok, default} <- File.read("config/emoji.txt") do
custom =
with {:ok, custom} <- File.read("config/custom_emoji.txt") do
custom
else
_e -> ""
end
(default <> "\n" <> custom)
|> String.trim()
|> String.split(~r/\n+/)
|> Enum.map(fn(line) ->
[name, file] = String.split(line, ~r/,\s*/)
{name, file}
end)
else
_ -> []
end)
@emoji @finmoji_with_filenames ++ @emoji_from_file
- def emojify(text, additional \\ nil) do
- all_emoji = if additional do
- Map.to_list(additional) ++ @emoji
- else
- @emoji
- end
-
- Enum.reduce(all_emoji, text, fn ({emoji, file}, text) ->
+ def emojify(text, emoji \\ @emoji)
+ def emojify(text, nil), do: text
+ def emojify(text, emoji) do
+ Enum.reduce(emoji, text, fn ({emoji, file}, text) ->
emoji = HtmlSanitizeEx.strip_tags(emoji)
file = HtmlSanitizeEx.strip_tags(file)
String.replace(text, ":#{emoji}:", "<img height='32px' width='32px' alt='#{emoji}' title='#{emoji}' src='#{MediaProxy.url(file)}' />")
end)
end
def get_emoji(text) do
Enum.filter(@emoji, fn ({emoji, _}) -> String.contains?(text, ":#{emoji}:") end)
end
def get_custom_emoji() do
@emoji
end
@link_regex ~r/https?:\/\/[\w\.\/?=\-#%&@~\(\)]+[\w\/]/u
def html_escape(text) do
Regex.split(@link_regex, text, include_captures: true)
|> Enum.map_every(2, fn chunk ->
{:safe, part} = Phoenix.HTML.html_escape(chunk)
part
end)
|> Enum.join("")
end
@doc "changes http:... links to html links"
def add_links({subs, text}) do
links = Regex.scan(@link_regex, text)
|> Enum.map(fn ([url]) -> {Ecto.UUID.generate, url} end)
uuid_text = links
|> Enum.reduce(text, fn({uuid, url}, acc) -> String.replace(acc, url, uuid) end)
subs = subs ++ Enum.map(links, fn({uuid, url}) ->
{uuid, "<a href='#{url}'>#{url}</a>"}
end)
{subs, uuid_text}
end
@doc "Adds the links to mentioned users"
def add_user_links({subs, text}, mentions) do
mentions = mentions
|> Enum.sort_by(fn ({name, _}) -> -String.length(name) end)
|> Enum.map(fn({name, user}) -> {name, user, Ecto.UUID.generate} end)
uuid_text = mentions
|> Enum.reduce(text, fn ({match, _user, uuid}, text) ->
String.replace(text, match, uuid)
end)
subs = subs ++ Enum.map(mentions, fn ({match, %User{ap_id: ap_id}, uuid}) ->
short_match = String.split(match, "@") |> tl() |> hd()
{uuid, "<span><a href='#{ap_id}'>@<span>#{short_match}</span></a></span>"}
end)
{subs, uuid_text}
end
@doc "Adds the hashtag links"
def add_hashtag_links({subs, text}, tags) do
tags = tags
|> Enum.sort_by(fn ({name, _}) -> -String.length(name) end)
|> Enum.map(fn({name, short}) -> {name, short, Ecto.UUID.generate} end)
uuid_text = tags
|> Enum.reduce(text, fn ({match, _short, uuid}, text) ->
String.replace(text, match, uuid)
end)
subs = subs ++ Enum.map(tags, fn ({_, tag, uuid}) ->
url = "<a href='#{Pleroma.Web.base_url}/tag/#{tag}' rel='tag'>##{tag}</a>"
{uuid, url}
end)
{subs, uuid_text}
end
def finalize({subs, text}) do
Enum.reduce(subs, text, fn({uuid, replacement}, result_text) ->
String.replace(result_text, uuid, replacement)
end)
end
end
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 5199cef8e..73ae3422b 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -1,192 +1,193 @@
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.CommonAPI.Utils
alias Pleroma.Formatter
defp user_by_ap_id(user_list, ap_id) do
Enum.find(user_list, fn (%{ap_id: user_id}) -> ap_id == user_id end)
end
def to_map(%Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} = activity,
%{users: users, announced_activity: announced_activity} = opts) do
user = user_by_ap_id(users, actor)
created_at = created_at |> Utils.date_to_asctime
text = "#{user.nickname} retweeted a status."
announced_user = user_by_ap_id(users, announced_activity.data["actor"])
retweeted_status = to_map(announced_activity, Map.merge(%{user: announced_user}, opts))
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"statusnet_html" => text,
"text" => text,
"is_local" => activity.local,
"is_post_verb" => false,
"uri" => "tag:#{activity.data["id"]}:objectType=note",
"created_at" => created_at,
"retweeted_status" => retweeted_status,
"statusnet_conversation_id" => conversation_id(announced_activity),
"external_url" => activity.data["id"],
"activity_type" => "repeat"
}
end
def to_map(%Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
%{user: user, liked_activity: liked_activity} = opts) do
created_at = created_at |> Utils.date_to_asctime
text = "#{user.nickname} favorited a status."
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"statusnet_html" => text,
"text" => text,
"is_local" => activity.local,
"is_post_verb" => false,
"uri" => "tag:#{activity.data["id"]}:objectType=Favourite",
"created_at" => created_at,
"in_reply_to_status_id" => liked_activity.id,
"external_url" => activity.data["id"],
"activity_type" => "like"
}
end
def to_map(%Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity, %{user: user} = opts) do
created_at = activity.data["published"] || (DateTime.to_iso8601(activity.inserted_at))
created_at = created_at |> Utils.date_to_asctime
followed = User.get_cached_by_ap_id(followed_id)
text = "#{user.nickname} started following #{followed.nickname}"
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"attentions" => [],
"statusnet_html" => text,
"text" => text,
"is_local" => activity.local,
"is_post_verb" => false,
"created_at" => created_at,
"in_reply_to_status_id" => nil,
"external_url" => activity.data["id"],
"activity_type" => "follow"
}
end
# TODO:
# Make this more proper. Just a placeholder to not break the frontend.
def to_map(%Activity{data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity }} = activity, %{user: user} = opts) do
created_at = created_at |> Utils.date_to_asctime
text = "#{user.nickname} undid the action at #{undid_activity}"
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"attentions" => [],
"statusnet_html" => text,
"text" => text,
"is_local" => activity.local,
"is_post_verb" => false,
"created_at" => created_at,
"in_reply_to_status_id" => nil,
"external_url" => activity.data["id"],
"activity_type" => "undo"
}
end
def to_map(%Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _ }} = activity, %{user: user} = opts) do
created_at = created_at |> Utils.date_to_asctime
%{
"id" => activity.id,
"uri" => activity.data["object"],
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"attentions" => [],
"statusnet_html" => "deleted notice {{tag",
"text" => "deleted notice {{tag" ,
"is_local" => activity.local,
"is_post_verb" => false,
"created_at" => created_at,
"in_reply_to_status_id" => nil,
"external_url" => activity.data["id"],
"activity_type" => "delete"
}
end
def to_map(%Activity{data: %{"object" => %{"content" => content} = object}} = activity, %{user: user} = opts) do
created_at = object["published"] |> Utils.date_to_asctime
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
mentions = opts[:mentioned] || []
attentions = activity.recipients
|> Enum.map(fn (ap_id) -> Enum.find(mentions, fn(user) -> ap_id == user.ap_id end) end)
|> Enum.filter(&(&1))
|> Enum.map(fn (user) -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
conversation_id = conversation_id(activity)
tags = activity.data["object"]["tag"] || []
possibly_sensitive = activity.data["object"]["sensitive"] || Enum.member?(tags, "nsfw")
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
- html = HtmlSanitizeEx.basic_html(content) |> Formatter.emojify(object["emoji"])
+ html = HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"statusnet_html" => html,
"text" => HtmlSanitizeEx.strip_tags(content),
"is_local" => activity.local,
"is_post_verb" => true,
"created_at" => created_at,
"in_reply_to_status_id" => object["inReplyToStatusId"],
"statusnet_conversation_id" => conversation_id,
"attachments" => (object["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
"attentions" => attentions,
"fave_num" => like_count,
"repeat_num" => announcement_count,
"favorited" => to_boolean(favorited),
"repeated" => to_boolean(repeated),
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
"possibly_sensitive" => possibly_sensitive
}
end
def conversation_id(activity) do
with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
else _e -> nil
end
end
defp to_boolean(false) do
false
end
defp to_boolean(nil) do
false
end
defp to_boolean(_) do
true
end
end
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 76b8cb14b..ae5be60ce 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -1,72 +1,73 @@
defmodule Pleroma.Web.TwitterAPI.ActivityView do
use Pleroma.Web, :view
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.User
alias Pleroma.Web.TwitterAPI.UserView
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
alias Pleroma.Formatter
def render("activity.json", %{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts) do
actor = get_in(activity.data, ["actor"])
user = User.get_cached_by_ap_id(actor)
created_at = object["published"] |> Utils.date_to_asctime
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
attentions = activity.recipients
|> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
|> Enum.filter(&(&1))
|> Enum.map(fn (user) -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
conversation_id = conversation_id(activity)
tags = activity.data["object"]["tag"] || []
possibly_sensitive = activity.data["object"]["sensitive"] || Enum.member?(tags, "nsfw")
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
- html = HtmlSanitizeEx.basic_html(content) |> Formatter.emojify(object["emoji"])
+ html = HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
%{
"id" => activity.id,
"uri" => activity.data["object"]["id"],
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"statusnet_html" => html,
"text" => HtmlSanitizeEx.strip_tags(content),
"is_local" => activity.local,
"is_post_verb" => true,
"created_at" => created_at,
"in_reply_to_status_id" => object["inReplyToStatusId"],
"statusnet_conversation_id" => conversation_id,
"attachments" => (object["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
"attentions" => attentions,
"fave_num" => like_count,
"repeat_num" => announcement_count,
"favorited" => !!favorited,
"repeated" => !!repeated,
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
"possibly_sensitive" => possibly_sensitive
}
end
defp conversation_id(activity) do
with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
else _e -> nil
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Sep 18, 10:19 PM (10 m, 12 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1766943
Default Alt Text
(16 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment