diff --git a/config/config.exs b/config/config.exs
index 9f0f4cd4f..1c55807b7 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -138,7 +138,8 @@
],
finmoji_enabled: true,
mrf_transparency: true,
- autofollowed_nicknames: []
+ autofollowed_nicknames: [],
+ max_pinned_statuses: 1
config :pleroma, :markup,
# XXX - unfortunately, inline images must be enabled by default right now, because
diff --git a/docs/config.md b/docs/config.md
index 1a9706f5b..7eb2d5671 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -32,7 +32,7 @@ This filter replaces the filename (not the path) of an upload. For complete obfu
## Pleroma.Mailer
* `adapter`: one of the mail adapters listed in [Swoosh readme](https://github.com/swoosh/swoosh#adapters), or `Swoosh.Adapters.Local` for in-memory mailbox.
-* `api_key` / `password` and / or other adapter-specific settings, per the above documentation.
+* `api_key` / `password` and / or other adapter-specific settings, per the above documentation.
An example for Sendgrid adapter:
@@ -93,6 +93,7 @@ config :pleroma, Pleroma.Mailer,
* `always_show_subject_input`: When set to false, auto-hide the subject field when it's empty.
* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
older software for theses nicknames.
+* `max_pinned_statuses`: The maximum number of pinned statuses. `0` will disable the feature.
* `autofollowed_nicknames`: Set to nicknames of (local) users that every new user should automatically follow.
## :logger
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 7c79dfcff..fb1791c20 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -31,6 +31,7 @@ defmodule Pleroma.User.Info do
field(:hub, :string, default: nil)
field(:salmon, :string, default: nil)
field(:hide_network, :boolean, default: false)
+ field(:pinned_activities, {:array, :integer}, default: [])
# Found in the wild
# ap_id -> Where is this used?
@@ -196,4 +197,26 @@ def admin_api_update(info, params) do
:is_admin
])
end
+
+ def add_pinnned_activity(info, %Pleroma.Activity{id: id}) do
+ if id not in info.pinned_activities do
+ max_pinned_statuses = Pleroma.Config.get([:instance, :max_pinned_statuses], 0)
+ params = %{pinned_activities: info.pinned_activities ++ [id]}
+
+ info
+ |> cast(params, [:pinned_activities])
+ |> validate_length(:pinned_activities,
+ max: max_pinned_statuses,
+ message: "You have already pinned the maximum number of statuses"
+ )
+ else
+ change(info)
+ end
+ end
+
+ def remove_pinnned_activity(info, %Pleroma.Activity{id: id}) do
+ params = %{pinned_activities: List.delete(info.pinned_activities, id)}
+
+ cast(info, params, [:pinned_activities])
+ end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index b8141146f..9c1eb377f 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -391,6 +391,7 @@ def fetch_user_activities(user, reading_user, params \\ %{}) do
|> Map.put("type", ["Create", "Announce"])
|> Map.put("actor_id", user.ap_id)
|> Map.put("whole_db", true)
+ |> Map.put("pinned_activity_ids", user.info.pinned_activities)
recipients =
if reading_user do
@@ -549,6 +550,12 @@ defp restrict_unlisted(query) do
)
end
+ defp restrict_pinned(query, %{"pinned" => "true", "pinned_activity_ids" => ids}) do
+ from(activity in query, where: activity.id in ^ids)
+ end
+
+ defp restrict_pinned(query, _), do: query
+
def fetch_activities_query(recipients, opts \\ %{}) do
base_query =
from(
@@ -573,6 +580,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|> restrict_visibility(opts)
|> restrict_replies(opts)
|> restrict_reblogs(opts)
+ |> restrict_pinned(opts)
end
def fetch_activities(recipients, opts \\ %{}) do
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index bb3c38f00..7ec6aa0ea 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -164,4 +164,48 @@ def update(user) do
object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
})
end
+
+ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
+ with %Activity{
+ actor: ^user_ap_id,
+ data: %{
+ "type" => "Create",
+ "object" => %{
+ "to" => object_to,
+ "type" => "Note"
+ }
+ }
+ } = activity <- get_by_id_or_ap_id(id_or_ap_id),
+ true <- Enum.member?(object_to, "https://www.w3.org/ns/activitystreams#Public"),
+ %{valid?: true} = info_changeset <-
+ Pleroma.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, activity}
+ else
+ %{errors: [pinned_activities: {err, _}]} ->
+ {:error, err}
+
+ _ ->
+ {:error, "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 <-
+ Pleroma.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, activity}
+ else
+ %{errors: [pinned_activities: {err, _}]} ->
+ {:error, err}
+
+ _ ->
+ {:error, "Could not unpin"}
+ end
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index f739e8f7d..e00a3fb87 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -256,13 +256,7 @@ def public_timeline(%{assigns: %{user: user}} = conn, params) do
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
with %User{} = user <- Repo.get(User, params["id"]) do
- # Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
- activities =
- if params["pinned"] == "true" do
- []
- else
- ActivityPub.fetch_user_activities(user, reading_user, params)
- end
+ activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
|> add_link_headers(:user_statuses, activities, params["id"])
@@ -409,6 +403,27 @@ def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
end
end
+ def pin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ else
+ {:error, reason} ->
+ conn
+ |> put_resp_content_type("application/json")
+ |> send_resp(:bad_request, Jason.encode!(%{"error" => reason}))
+ end
+ end
+
+ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
+ conn
+ |> put_view(StatusView)
+ |> try_render("status.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
def notifications(%{assigns: %{user: user}} = conn, params) do
notifications = Notification.for_user(user, params)
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 8e8fa8121..db543ffe5 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -76,6 +76,7 @@ def render(
reblogged: false,
favourited: false,
muted: false,
+ pinned: pinned?(activity, user),
sensitive: false,
spoiler_text: "",
visibility: "public",
@@ -142,6 +143,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
reblogged: present?(repeated),
favourited: present?(favorited),
muted: false,
+ pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: object["summary"] || "",
visibility: get_visibility(object),
@@ -295,4 +297,7 @@ def build_emojis(emojis) do
defp present?(nil), do: false
defp present?(false), do: false
defp present?(_), do: true
+
+ defp pinned?(%Activity{id: id}, %User{info: %{pinned_activities: pinned_activities}}),
+ do: id in pinned_activities
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 8df45bf4d..a5f4d8126 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -188,6 +188,8 @@ defmodule Pleroma.Web.Router do
post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
+ post("/statuses/:id/pin", MastodonAPIController, :pin_status)
+ post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
post("/notifications/clear", MastodonAPIController, :clear_notifications)
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
@@ -353,6 +355,9 @@ defmodule Pleroma.Web.Router do
post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet)
post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
+ post("/statuses/pin/:id", TwitterAPI.Controller, :pin)
+ post("/statuses/unpin/:id", TwitterAPI.Controller, :unpin)
+
get("/pleroma/friend_requests", TwitterAPI.Controller, :friend_requests)
post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request)
post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request)
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 47154829d..4f8f228ab 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -153,6 +153,7 @@ def to_map(
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"] || [])
+ pinned = activity.id in user.info.pinned_activities
mentions = opts[:mentioned] || []
@@ -204,6 +205,7 @@ def to_map(
"repeat_num" => announcement_count,
"favorited" => to_boolean(favorited),
"repeated" => to_boolean(repeated),
+ "pinned" => pinned,
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index ecf81d492..7a63724f1 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -82,6 +82,14 @@ def unrepeat(%User{} = user, ap_id_or_id) do
end
end
+ def pin(%User{} = user, ap_id_or_id) do
+ CommonAPI.pin(ap_id_or_id, user)
+ end
+
+ def unpin(%User{} = user, ap_id_or_id) do
+ CommonAPI.unpin(ap_id_or_id, user)
+ end
+
def fav(%User{} = user, ap_id_or_id) do
with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 1e04b8c4b..d5b9d2fb8 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -375,6 +375,30 @@ def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
end
+ def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+ {:ok, activity} <- TwitterAPI.pin(user, id) do
+ conn
+ |> put_view(ActivityView)
+ |> render("activity.json", %{activity: activity, for: user})
+ else
+ {:error, message} -> bad_request_reply(conn, message)
+ err -> err
+ end
+ end
+
+ def unpin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
+ {:ok, activity} <- TwitterAPI.unpin(user, id) do
+ conn
+ |> put_view(ActivityView)
+ |> render("activity.json", %{activity: activity, for: user})
+ else
+ {:error, message} -> bad_request_reply(conn, message)
+ err -> err
+ end
+ end
+
def register(conn, params) do
with {:ok, user} <- TwitterAPI.register_user(params) do
conn
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 5f4b74842..108e7bfc5 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -243,6 +243,7 @@ def render(
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"] || [])
+ pinned = activity.id in user.info.pinned_activities
attentions =
activity.recipients
@@ -302,6 +303,7 @@ def render(
"repeat_num" => announcement_count,
"favorited" => !!favorited,
"repeated" => !!repeated,
+ "pinned" => pinned,
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 47aa5a56f..eafb96f3a 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -637,6 +637,28 @@ test "it can fetch peertube videos" do
assert object
end
+ test "returned pinned statuses" do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 3)
+ user = insert(:user)
+
+ {:ok, activity_one} = CommonAPI.post(user, %{"status" => "HI!!!"})
+ {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+ {:ok, activity_three} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ CommonAPI.pin(activity_one.id, user)
+ user = refresh_record(user)
+
+ CommonAPI.pin(activity_two.id, user)
+ user = refresh_record(user)
+
+ CommonAPI.pin(activity_three.id, user)
+ user = refresh_record(user)
+
+ activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"})
+
+ assert 3 = length(activities)
+ end
+
def data_uri do
File.read!("test/fixtures/avatar_data_uri")
end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index c3674711a..eb69ea4b2 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.CommonAPI.Test do
@@ -96,4 +96,42 @@ test "favoriting a status twice returns an error" do
{:error, _} = CommonAPI.favorite(activity.id, user)
end
end
+
+ describe "pinned statuses" do
+ setup do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ [user: user, activity: activity]
+ end
+
+ test "pin status", %{user: user, activity: activity} do
+ assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
+ end
+
+ test "only self-authored can be pinned", %{activity: activity} do
+ user = insert(:user)
+
+ assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
+ end
+
+ test "max pinned statuses", %{user: user, activity: activity_one} do
+ {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ assert {:ok, ^activity_one} = CommonAPI.pin(activity_one.id, user)
+
+ user = refresh_record(user)
+
+ assert {:error, "You have already pinned the maximum number of statuses"} =
+ CommonAPI.pin(activity_two.id, user)
+ end
+
+ test "unpin status", %{user: user, activity: activity} do
+ {:ok, activity} = CommonAPI.pin(activity.id, user)
+
+ assert {:ok, ^activity} = CommonAPI.unpin(activity.id, user)
+ end
+ end
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index ce87010c8..b448d13f5 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
@@ -1471,4 +1471,84 @@ test "put settings", %{conn: conn} do
user = User.get_cached_by_ap_id(user.ap_id)
assert user.info.settings == %{"programming" => "socks"}
end
+
+ describe "pinned statuses" do
+ setup do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ [user: user, activity: activity]
+ end
+
+ test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.pin(activity.id, user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+ |> json_response(200)
+
+ id_str = to_string(activity.id)
+
+ assert [%{"id" => ^id_str, "pinned" => true}] = result
+ end
+
+ test "pin status", %{conn: conn, user: user, activity: activity} do
+ id_str = to_string(activity.id)
+
+ assert %{"id" => ^id_str, "pinned" => true} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/pin")
+ |> json_response(200)
+
+ assert [%{"id" => ^id_str, "pinned" => true}] =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+ |> json_response(200)
+ end
+
+ test "unpin status", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.pin(activity.id, user)
+
+ id_str = to_string(activity.id)
+ user = refresh_record(user)
+
+ assert %{"id" => ^id_str, "pinned" => false} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unpin")
+ |> json_response(200)
+
+ assert [] =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+ |> json_response(200)
+ end
+
+ test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
+ {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ id_str_one = to_string(activity_one.id)
+
+ assert %{"id" => ^id_str_one, "pinned" => true} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{id_str_one}/pin")
+ |> json_response(200)
+
+ user = refresh_record(user)
+
+ assert %{"error" => "You have already pinned the maximum number of statuses"} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity_two.id}/pin")
+ |> json_response(400)
+ end
+ end
end
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index b953ccd76..1076b5002 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -63,6 +63,7 @@ test "a note activity" do
reblogged: false,
favourited: false,
muted: false,
+ pinned: false,
sensitive: false,
spoiler_text: note.data["object"]["summary"],
visibility: "public",
diff --git a/test/web/twitter_api/representers/activity_representer_test.exs b/test/web/twitter_api/representers/activity_representer_test.exs
index d71aaacfe..ef0294140 100644
--- a/test/web/twitter_api/representers/activity_representer_test.exs
+++ b/test/web/twitter_api/representers/activity_representer_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
@@ -157,6 +157,7 @@ test "an activity" do
"repeat_num" => 3,
"favorited" => false,
"repeated" => false,
+ "pinned" => false,
"external_url" => "some url",
"tags" => ["nsfw", "content", "mentioning"],
"activity_type" => "post",
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs
index c41f615ac..7d4c92c66 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/web/twitter_api/twitter_api_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.ControllerTest do
@@ -1694,4 +1694,79 @@ test "it updates `data[name]` of referenced Object with provided value", %{
assert object.data["name"] == description
end
end
+
+ describe "POST /api/statuses/user_timeline.json?user_id=:user_id&pinned=true" do
+ test "it returns a list of pinned statuses", %{conn: conn} do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+
+ user = insert(:user, %{name: "egor"})
+ {:ok, %{id: activity_id}} = CommonAPI.post(user, %{"status" => "HI!!!"})
+ {:ok, _} = CommonAPI.pin(activity_id, user)
+
+ resp =
+ conn
+ |> get("/api/statuses/user_timeline.json", %{user_id: user.id, pinned: true})
+ |> json_response(200)
+
+ assert length(resp) == 1
+ assert [%{"id" => ^activity_id, "pinned" => true}] = resp
+ end
+ end
+
+ describe "POST /api/statuses/pin/:id" do
+ setup do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+ [user: insert(:user)]
+ end
+
+ test "without valid credentials", %{conn: conn} do
+ note_activity = insert(:note_activity)
+ conn = post(conn, "/api/statuses/pin/#{note_activity.id}.json")
+ assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+ end
+
+ test "with credentials", %{conn: conn, user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
+
+ request_path = "/api/statuses/pin/#{activity.id}.json"
+
+ response =
+ conn
+ |> with_credentials(user.nickname, "test")
+ |> post(request_path)
+
+ user = refresh_record(user)
+
+ assert json_response(response, 200) == ActivityRepresenter.to_map(activity, %{user: user})
+ end
+ end
+
+ describe "POST /api/statuses/unpin/:id" do
+ setup do
+ Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+ [user: insert(:user)]
+ end
+
+ test "without valid credentials", %{conn: conn} do
+ note_activity = insert(:note_activity)
+ conn = post(conn, "/api/statuses/unpin/#{note_activity.id}.json")
+ assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
+ end
+
+ test "with credentials", %{conn: conn, user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test!"})
+ {:ok, activity} = CommonAPI.pin(activity.id, user)
+
+ request_path = "/api/statuses/unpin/#{activity.id}.json"
+
+ response =
+ conn
+ |> with_credentials(user.nickname, "test")
+ |> post(request_path)
+
+ user = refresh_record(user)
+
+ assert json_response(response, 200) == ActivityRepresenter.to_map(activity, %{user: user})
+ end
+ end
end
diff --git a/test/web/twitter_api/views/activity_view_test.exs b/test/web/twitter_api/views/activity_view_test.exs
index 5294204c6..8b5a16add 100644
--- a/test/web/twitter_api/views/activity_view_test.exs
+++ b/test/web/twitter_api/views/activity_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors
+# Copyright © 2017-2019 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
@@ -136,6 +136,7 @@ test "a create activity with a note" do
"possibly_sensitive" => false,
"repeat_num" => 0,
"repeated" => false,
+ "pinned" => false,
"statusnet_conversation_id" => convo_id,
"summary" => "",
"summary_html" => "",