Added limits and media attachments for scheduled activities.
This commit is contained in:
parent
b3870df51f
commit
fc92a0fd8d
|
@ -367,6 +367,10 @@
|
||||||
enabled: false,
|
enabled: false,
|
||||||
pages: 5
|
pages: 5
|
||||||
|
|
||||||
|
config :pleroma, Pleroma.ScheduledActivity,
|
||||||
|
daily_user_limit: 25,
|
||||||
|
total_user_limit: 100
|
||||||
|
|
||||||
config :auto_linker,
|
config :auto_linker,
|
||||||
opts: [
|
opts: [
|
||||||
scheme: true,
|
scheme: true,
|
||||||
|
|
|
@ -412,3 +412,8 @@ Pleroma account will be created with the same name as the LDAP user name.
|
||||||
|
|
||||||
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
|
* `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator
|
||||||
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
|
* `Pleroma.Web.Auth.LDAPAuthenticator`: LDAP authentication
|
||||||
|
|
||||||
|
## Pleroma.ScheduledActivity
|
||||||
|
|
||||||
|
* `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day
|
||||||
|
* `total_user_limit`: the number of scheduled activities a user is allowed to create in total
|
||||||
|
|
|
@ -184,4 +184,12 @@ def decrease_replies_count(ap_id) do
|
||||||
_ -> {:error, "Not found"}
|
_ -> {:error, "Not found"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enforce_user_objects(user, object_ids) do
|
||||||
|
Object
|
||||||
|
|> where([o], fragment("?->>'actor' = ?", o.data, ^user.ap_id))
|
||||||
|
|> where([o], o.id in ^object_ids)
|
||||||
|
|> select([o], o.id)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,9 +5,12 @@
|
||||||
defmodule Pleroma.ScheduledActivity do
|
defmodule Pleroma.ScheduledActivity do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.ScheduledActivity
|
alias Pleroma.ScheduledActivity
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -25,11 +28,69 @@ defmodule Pleroma.ScheduledActivity do
|
||||||
def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
|
def changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
|
||||||
scheduled_activity
|
scheduled_activity
|
||||||
|> cast(attrs, [:scheduled_at, :params])
|
|> cast(attrs, [:scheduled_at, :params])
|
||||||
|
|> validate_required([:scheduled_at, :params])
|
||||||
|
|> validate_scheduled_at()
|
||||||
|
|> with_media_attachments()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp with_media_attachments(
|
||||||
|
%{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
|
||||||
|
)
|
||||||
|
when is_list(media_ids) do
|
||||||
|
user = User.get_cached_by_id(changeset.data.user_id)
|
||||||
|
media_ids = Object.enforce_user_objects(user, media_ids) |> Enum.map(&to_string(&1))
|
||||||
|
media_attachments = Utils.attachments_from_ids(%{"media_ids" => media_ids})
|
||||||
|
|
||||||
|
params =
|
||||||
|
params
|
||||||
|
|> Map.put("media_attachments", media_attachments)
|
||||||
|
|> Map.put("media_ids", media_ids)
|
||||||
|
|
||||||
|
put_change(changeset, :params, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp with_media_attachments(changeset), do: changeset
|
||||||
|
|
||||||
def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
|
def update_changeset(%ScheduledActivity{} = scheduled_activity, attrs) do
|
||||||
scheduled_activity
|
scheduled_activity
|
||||||
|> cast(attrs, [:scheduled_at])
|
|> cast(attrs, [:scheduled_at])
|
||||||
|
|> validate_required([:scheduled_at])
|
||||||
|
|> validate_scheduled_at()
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_scheduled_at(changeset) do
|
||||||
|
validate_change(changeset, :scheduled_at, fn _, scheduled_at ->
|
||||||
|
cond do
|
||||||
|
not far_enough?(scheduled_at) ->
|
||||||
|
[scheduled_at: "must be at least 5 minutes from now"]
|
||||||
|
|
||||||
|
exceeds_daily_user_limit?(changeset.data.user_id, scheduled_at) ->
|
||||||
|
[scheduled_at: "daily limit exceeded"]
|
||||||
|
|
||||||
|
exceeds_total_user_limit?(changeset.data.user_id) ->
|
||||||
|
[scheduled_at: "total limit exceeded"]
|
||||||
|
|
||||||
|
true ->
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exceeds_daily_user_limit?(user_id, scheduled_at) do
|
||||||
|
ScheduledActivity
|
||||||
|
|> where(user_id: ^user_id)
|
||||||
|
|> where([s], type(s.scheduled_at, :date) == type(^scheduled_at, :date))
|
||||||
|
|> select([u], count(u.id))
|
||||||
|
|> Repo.one()
|
||||||
|
|> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit]))
|
||||||
|
end
|
||||||
|
|
||||||
|
def exceeds_total_user_limit?(user_id) do
|
||||||
|
ScheduledActivity
|
||||||
|
|> where(user_id: ^user_id)
|
||||||
|
|> select([u], count(u.id))
|
||||||
|
|> Repo.one()
|
||||||
|
|> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit]))
|
||||||
end
|
end
|
||||||
|
|
||||||
def far_enough?(scheduled_at) when is_binary(scheduled_at) do
|
def far_enough?(scheduled_at) when is_binary(scheduled_at) do
|
||||||
|
@ -64,23 +125,15 @@ def get(%User{} = user, scheduled_activity_id) do
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(%User{} = user, scheduled_activity_id, attrs) do
|
def update(scheduled_activity, attrs) do
|
||||||
with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
|
scheduled_activity
|
||||||
scheduled_activity
|
|> update_changeset(attrs)
|
||||||
|> update_changeset(attrs)
|
|> Repo.update()
|
||||||
|> Repo.update()
|
|
||||||
else
|
|
||||||
nil -> {:error, :not_found}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(%User{} = user, scheduled_activity_id) do
|
def delete(scheduled_activity) do
|
||||||
with %ScheduledActivity{} = scheduled_activity <- get(user, scheduled_activity_id) do
|
scheduled_activity
|
||||||
scheduled_activity
|
|> Repo.delete()
|
||||||
|> Repo.delete()
|
|
||||||
else
|
|
||||||
nil -> {:error, :not_found}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def for_user_query(%User{} = user) do
|
def for_user_query(%User{} = user) do
|
||||||
|
|
|
@ -390,18 +390,28 @@ def update_scheduled_status(
|
||||||
%{assigns: %{user: user}} = conn,
|
%{assigns: %{user: user}} = conn,
|
||||||
%{"id" => scheduled_activity_id} = params
|
%{"id" => scheduled_activity_id} = params
|
||||||
) do
|
) do
|
||||||
with {:ok, scheduled_activity} <-
|
with %ScheduledActivity{} = scheduled_activity <-
|
||||||
ScheduledActivity.update(user, scheduled_activity_id, params) do
|
ScheduledActivity.get(user, scheduled_activity_id),
|
||||||
|
{:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
|
||||||
conn
|
conn
|
||||||
|> put_view(ScheduledActivityView)
|
|> put_view(ScheduledActivityView)
|
||||||
|> render("show.json", %{scheduled_activity: scheduled_activity})
|
|> render("show.json", %{scheduled_activity: scheduled_activity})
|
||||||
|
else
|
||||||
|
nil -> {:error, :not_found}
|
||||||
|
error -> error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
|
def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do
|
||||||
with {:ok, %ScheduledActivity{}} <- ScheduledActivity.delete(user, scheduled_activity_id) do
|
with %ScheduledActivity{} = scheduled_activity <-
|
||||||
|
ScheduledActivity.get(user, scheduled_activity_id),
|
||||||
|
{:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do
|
||||||
conn
|
conn
|
||||||
|> json(%{})
|
|> put_view(ScheduledActivityView)
|
||||||
|
|> render("show.json", %{scheduled_activity: scheduled_activity})
|
||||||
|
else
|
||||||
|
nil -> {:error, :not_found}
|
||||||
|
error -> error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
|
||||||
alias Pleroma.ScheduledActivity
|
alias Pleroma.ScheduledActivity
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
|
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
|
||||||
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
|
||||||
def render("index.json", %{scheduled_activities: scheduled_activities}) do
|
def render("index.json", %{scheduled_activities: scheduled_activities}) do
|
||||||
render_many(scheduled_activities, ScheduledActivityView, "show.json")
|
render_many(scheduled_activities, ScheduledActivityView, "show.json")
|
||||||
|
@ -17,7 +18,36 @@ def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_a
|
||||||
%{
|
%{
|
||||||
id: scheduled_activity.id |> to_string,
|
id: scheduled_activity.id |> to_string,
|
||||||
scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(),
|
scheduled_at: scheduled_activity.scheduled_at |> CommonAPI.Utils.to_masto_date(),
|
||||||
params: scheduled_activity.params
|
params: status_params(scheduled_activity.params)
|
||||||
}
|
}
|
||||||
|
|> with_media_attachments(scheduled_activity)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do
|
||||||
|
attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
|
||||||
|
Map.put(data, :media_attachments, attachments)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp with_media_attachments(data, _), do: data
|
||||||
|
|
||||||
|
defp status_params(params) do
|
||||||
|
data = %{
|
||||||
|
text: params["status"],
|
||||||
|
sensitive: params["sensitive"],
|
||||||
|
spoiler_text: params["spoiler_text"],
|
||||||
|
visibility: params["visibility"],
|
||||||
|
scheduled_at: params["scheduled_at"],
|
||||||
|
poll: params["poll"],
|
||||||
|
in_reply_to_id: params["in_reply_to_id"]
|
||||||
|
}
|
||||||
|
|
||||||
|
data =
|
||||||
|
if media_ids = params["media_ids"] do
|
||||||
|
Map.put(data, :media_ids, media_ids)
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,5 +11,6 @@ def change do
|
||||||
end
|
end
|
||||||
|
|
||||||
create(index(:scheduled_activities, [:scheduled_at]))
|
create(index(:scheduled_activities, [:scheduled_at]))
|
||||||
|
create(index(:scheduled_activities, [:user_id]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.ScheduledActivityTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.Config
|
||||||
|
alias Pleroma.DataCase
|
||||||
|
alias Pleroma.ScheduledActivity
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup context do
|
||||||
|
Config.put([ScheduledActivity, :daily_user_limit], 2)
|
||||||
|
Config.put([ScheduledActivity, :total_user_limit], 3)
|
||||||
|
DataCase.ensure_local_uploader(context)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "creation" do
|
||||||
|
test "when daily user limit is exceeded" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
today =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
attrs = %{params: %{}, scheduled_at: today}
|
||||||
|
{:ok, _} = ScheduledActivity.create(user, attrs)
|
||||||
|
{:ok, _} = ScheduledActivity.create(user, attrs)
|
||||||
|
{:error, changeset} = ScheduledActivity.create(user, attrs)
|
||||||
|
assert changeset.errors == [scheduled_at: {"daily limit exceeded", []}]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "when total user limit is exceeded" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
today =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(6), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
tomorrow =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.hours(24), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today})
|
||||||
|
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: today})
|
||||||
|
{:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
|
||||||
|
{:error, changeset} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
|
||||||
|
assert changeset.errors == [scheduled_at: {"total limit exceeded", []}]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "when scheduled_at is earlier than 5 minute from now" do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
scheduled_at =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(4), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
attrs = %{params: %{}, scheduled_at: scheduled_at}
|
||||||
|
{:error, changeset} = ScheduledActivity.create(user, attrs)
|
||||||
|
assert changeset.errors == [scheduled_at: {"must be at least 5 minutes from now", []}]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "excludes attachments belonging to another user" do
|
||||||
|
user = insert(:user)
|
||||||
|
another_user = insert(:user)
|
||||||
|
|
||||||
|
scheduled_at =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(10), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, user_upload} = ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
{:ok, another_user_upload} = ActivityPub.upload(file, actor: another_user.ap_id)
|
||||||
|
|
||||||
|
media_ids = [user_upload.id, another_user_upload.id]
|
||||||
|
attrs = %{params: %{"media_ids" => media_ids}, scheduled_at: scheduled_at}
|
||||||
|
{:ok, scheduled_activity} = ScheduledActivity.create(user, attrs)
|
||||||
|
assert to_string(user_upload.id) in scheduled_activity.params["media_ids"]
|
||||||
|
refute to_string(another_user_upload.id) in scheduled_activity.params["media_ids"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,14 +23,6 @@ def user_factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def scheduled_activity_factory do
|
|
||||||
%Pleroma.ScheduledActivity{
|
|
||||||
user: build(:user),
|
|
||||||
scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
|
|
||||||
params: build(:note) |> Map.from_struct() |> Map.get(:data)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def note_factory(attrs \\ %{}) do
|
def note_factory(attrs \\ %{}) do
|
||||||
text = sequence(:text, &"This is :moominmamma: note #{&1}")
|
text = sequence(:text, &"This is :moominmamma: note #{&1}")
|
||||||
|
|
||||||
|
@ -275,4 +267,12 @@ def notification_factory do
|
||||||
user: build(:user)
|
user: build(:user)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def scheduled_activity_factory do
|
||||||
|
%Pleroma.ScheduledActivity{
|
||||||
|
user: build(:user),
|
||||||
|
scheduled_at: NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(60), :millisecond),
|
||||||
|
params: build(:note) |> Map.from_struct() |> Map.get(:data)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2427,6 +2427,31 @@ test "creates a scheduled activity", %{conn: conn} do
|
||||||
assert [] == Repo.all(Activity)
|
assert [] == Repo.all(Activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "creates a scheduled activity with a media attachment", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/v1/statuses", %{
|
||||||
|
"media_ids" => [to_string(upload.id)],
|
||||||
|
"status" => "scheduled",
|
||||||
|
"scheduled_at" => scheduled_at
|
||||||
|
})
|
||||||
|
|
||||||
|
assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
|
||||||
|
assert %{"type" => "image"} = media_attachment
|
||||||
|
end
|
||||||
|
|
||||||
test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
|
test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.ScheduledActivity
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
|
||||||
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
test "A scheduled activity with a media attachment" do
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{"status" => "hi"})
|
||||||
|
|
||||||
|
scheduled_at =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> NaiveDateTime.add(:timer.minutes(10), :millisecond)
|
||||||
|
|> NaiveDateTime.to_iso8601()
|
||||||
|
|
||||||
|
file = %Plug.Upload{
|
||||||
|
content_type: "image/jpg",
|
||||||
|
path: Path.absname("test/fixtures/image.jpg"),
|
||||||
|
filename: "an_image.jpg"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
|
||||||
|
|
||||||
|
attrs = %{
|
||||||
|
params: %{
|
||||||
|
"media_ids" => [upload.id],
|
||||||
|
"status" => "hi",
|
||||||
|
"sensitive" => true,
|
||||||
|
"spoiler_text" => "spoiler",
|
||||||
|
"visibility" => "unlisted",
|
||||||
|
"in_reply_to_id" => to_string(activity.id)
|
||||||
|
},
|
||||||
|
scheduled_at: scheduled_at
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, scheduled_activity} = ScheduledActivity.create(user, attrs)
|
||||||
|
result = ScheduledActivityView.render("show.json", %{scheduled_activity: scheduled_activity})
|
||||||
|
|
||||||
|
expected = %{
|
||||||
|
id: to_string(scheduled_activity.id),
|
||||||
|
media_attachments:
|
||||||
|
%{"media_ids" => [upload.id]}
|
||||||
|
|> Utils.attachments_from_ids()
|
||||||
|
|> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
|
||||||
|
params: %{
|
||||||
|
in_reply_to_id: to_string(activity.id),
|
||||||
|
media_ids: [to_string(upload.id)],
|
||||||
|
poll: nil,
|
||||||
|
scheduled_at: nil,
|
||||||
|
sensitive: true,
|
||||||
|
spoiler_text: "spoiler",
|
||||||
|
text: "hi",
|
||||||
|
visibility: "unlisted"
|
||||||
|
},
|
||||||
|
scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert expected == result
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue