utils.ex 5.07 KB
Newer Older
1
defmodule Pleroma.Web.CommonAPI.Utils do
feld's avatar
feld committed
2
  alias Pleroma.{Repo, Object, Formatter, Activity}
lain's avatar
lain committed
3
  alias Pleroma.Web.ActivityPub.Utils
4
  alias Pleroma.User
5
  alias Calendar.Strftime
6
  alias Comeonin.Pbkdf2
lain's avatar
lain committed
7

8 9 10
  # This is a hack for twidere.
  def get_by_id_or_ap_id(id) do
    activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
lain's avatar
lain committed
11

12 13 14 15 16 17
    activity &&
      if activity.data["type"] == "Create" do
        activity
      else
        Activity.get_create_activity_by_object_ap_id(activity.data["object"])
      end
18 19 20 21 22
  end

  def get_replied_to_activity(id) when not is_nil(id) do
    Repo.get(Activity, id)
  end
lain's avatar
lain committed
23

24 25
  def get_replied_to_activity(_), do: nil

lain's avatar
lain committed
26
  def attachments_from_ids(ids) do
lain's avatar
lain committed
27
    Enum.map(ids || [], fn media_id ->
lain's avatar
lain committed
28 29 30 31
      Repo.get(Object, media_id).data
    end)
  end

32 33
  def to_for_user_and_mentions(user, mentions, inReplyTo, "public") do
    to = ["https://www.w3.org/ns/activitystreams#Public"]
34

lain's avatar
lain committed
35
    mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)
36
    cc = [user.follower_address | mentioned_users]
lain's avatar
lain committed
37

38
    if inReplyTo do
39
      {to, Enum.uniq([inReplyTo.data["actor"] | cc])}
lain's avatar
lain committed
40
    else
41 42 43 44 45 46 47 48 49 50 51 52 53 54
      {to, cc}
    end
  end

  def to_for_user_and_mentions(user, mentions, inReplyTo, "unlisted") do
    {to, cc} = to_for_user_and_mentions(user, mentions, inReplyTo, "public")
    {cc, to}
  end

  def to_for_user_and_mentions(user, mentions, inReplyTo, "private") do
    {to, cc} = to_for_user_and_mentions(user, mentions, inReplyTo, "direct")
    {[user.follower_address | to], cc}
  end

55
  def to_for_user_and_mentions(_user, mentions, inReplyTo, "direct") do
lain's avatar
lain committed
56 57
    mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end)

58 59 60 61
    if inReplyTo do
      {Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
    else
      {mentioned_users, []}
lain's avatar
lain committed
62 63 64
    end
  end

eal's avatar
eal committed
65
  def make_content_html(status, mentions, attachments, tags, no_attachment_links \\ false) do
66
    status
kaniini's avatar
kaniini committed
67
    |> String.replace("\r", "")
lain's avatar
lain committed
68
    |> format_input(mentions, tags)
eal's avatar
eal committed
69
    |> maybe_add_attachments(attachments, no_attachment_links)
70 71 72
  end

  def make_context(%Activity{data: %{"context" => context}}), do: context
lain's avatar
lain committed
73
  def make_context(_), do: Utils.generate_context_id()
74

75
  def maybe_add_attachments(text, _attachments, _no_links = true), do: text
lain's avatar
lain committed
76

eal's avatar
eal committed
77 78 79
  def maybe_add_attachments(text, attachments, _no_links) do
    add_attachments(text, attachments)
  end
lain's avatar
lain committed
80

lain's avatar
lain committed
81
  def add_attachments(text, attachments) do
lain's avatar
lain committed
82 83 84 85 86 87 88 89 90 91
    attachment_text =
      Enum.map(attachments, fn
        %{"url" => [%{"href" => href} | _]} ->
          name = URI.decode(Path.basename(href))
          "<a href=\"#{href}\" class='attachment'>#{shortname(name)}</a>"

        _ ->
          ""
      end)

92
    Enum.join([text | attachment_text], "<br>")
lain's avatar
lain committed
93 94
  end

lain's avatar
lain committed
95
  def format_input(text, mentions, tags) do
eal's avatar
eal committed
96
    text
lain's avatar
lain committed
97
    |> Formatter.html_escape()
98
    |> String.replace("\n", "<br>")
lain's avatar
lain committed
99 100
    |> (&{[], &1}).()
    |> Formatter.add_links()
lain's avatar
lain committed
101 102
    |> Formatter.add_user_links(mentions)
    |> Formatter.add_hashtag_links(tags)
lain's avatar
lain committed
103
    |> Formatter.finalize()
lain's avatar
lain committed
104 105 106
  end

  def add_tag_links(text, tags) do
lain's avatar
lain committed
107 108 109
    tags =
      tags
      |> Enum.sort_by(fn {tag, _} -> -String.length(tag) end)
lain's avatar
lain committed
110

lain's avatar
lain committed
111
    Enum.reduce(tags, text, fn {full, tag}, text ->
kaniini's avatar
kaniini committed
112
      url = "<a href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>##{tag}</a>"
lain's avatar
lain committed
113 114
      String.replace(text, full, url)
    end)
lain's avatar
lain committed
115 116
  end

lain's avatar
lain committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
  def make_note_data(
        actor,
        to,
        context,
        content_html,
        attachments,
        inReplyTo,
        tags,
        cw \\ nil,
        cc \\ []
      ) do
    object = %{
      "type" => "Note",
      "to" => to,
      "cc" => cc,
      "content" => content_html,
      "summary" => cw,
      "context" => context,
      "attachment" => attachments,
      "actor" => actor,
137
      "tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq()
lain's avatar
lain committed
138
    }
lain's avatar
lain committed
139 140 141 142 143 144 145 146 147

    if inReplyTo do
      object
      |> Map.put("inReplyTo", inReplyTo.data["object"]["id"])
      |> Map.put("inReplyToStatusId", inReplyTo.id)
    else
      object
    end
  end
148 149 150 151 152 153 154 155 156 157

  def format_naive_asctime(date) do
    date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
  end

  def format_asctime(date) do
    Strftime.strftime!(date, "%a %b %d %H:%M:%S %z %Y")
  end

  def date_to_asctime(date) do
lain's avatar
lain committed
158
    with {:ok, date, _offset} <- date |> DateTime.from_iso8601() do
159
      format_asctime(date)
lain's avatar
lain committed
160 161
    else
      _e ->
162 163 164
        ""
    end
  end
165

166 167
  def to_masto_date(%NaiveDateTime{} = date) do
    date
lain's avatar
lain committed
168
    |> NaiveDateTime.to_iso8601()
169 170 171 172 173 174
    |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
  end

  def to_masto_date(date) do
    try do
      date
lain's avatar
lain committed
175 176
      |> NaiveDateTime.from_iso8601!()
      |> NaiveDateTime.to_iso8601()
177 178 179 180 181 182
      |> String.replace(~r/(\.\d+)?$/, ".000Z", global: false)
    rescue
      _e -> ""
    end
  end

183 184 185 186 187 188 189
  defp shortname(name) do
    if String.length(name) < 30 do
      name
    else
      String.slice(name, 0..30) <> "…"
    end
  end
190

191
  def confirm_current_password(user, password) do
192
    with %User{local: true} = db_user <- Repo.get(User, user.id),
193
         true <- Pbkdf2.checkpw(password, db_user.password_hash) do
194 195 196
      {:ok, db_user}
    else
      _ -> {:error, "Invalid password."}
197 198
    end
  end
lain's avatar
lain committed
199
end