Add ability to set a default post expiry (#321)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk> Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/321
This commit is contained in:
parent
2d019e14e3
commit
0cfd5b4e89
|
@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
## Added
|
||||
- Config: HTTP timeout options, :pool\_timeout and :receive\_timeout
|
||||
- Added statistic gathering about instances which do/don't have signed fetches when they request from us
|
||||
- Ability to set a default post expiry time, after which the post will be deleted. If used in concert with ActivityExpiration MRF, the expiry which comes _sooner_ will be applied.
|
||||
|
||||
## Changed
|
||||
- MastoAPI: Accept BooleanLike input on `/api/v1/accounts/:id/follow` (fixes follows with mastodon.py)
|
||||
|
|
|
@ -151,6 +151,7 @@ defmodule Pleroma.User do
|
|||
field(:is_suggested, :boolean, default: false)
|
||||
field(:last_status_at, :naive_datetime)
|
||||
field(:language, :string)
|
||||
field(:status_ttl_days, :integer, default: nil)
|
||||
|
||||
embeds_one(
|
||||
:notification_settings,
|
||||
|
@ -516,7 +517,8 @@ def update_changeset(struct, params \\ %{}) do
|
|||
:pleroma_settings_store,
|
||||
:is_discoverable,
|
||||
:actor_type,
|
||||
:disclose_client
|
||||
:disclose_client,
|
||||
:status_ttl_days
|
||||
]
|
||||
)
|
||||
|> unique_constraint(:nickname)
|
||||
|
@ -524,6 +526,7 @@ def update_changeset(struct, params \\ %{}) do
|
|||
|> validate_length(:bio, max: bio_limit)
|
||||
|> validate_length(:name, min: 1, max: name_limit)
|
||||
|> validate_inclusion(:actor_type, ["Person", "Service"])
|
||||
|> validate_number(:status_ttl_days, greater_than: 0)
|
||||
|> put_fields()
|
||||
|> put_emoji()
|
||||
|> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
|
||||
|
|
|
@ -700,7 +700,13 @@ defp update_credentials_request do
|
|||
description:
|
||||
"Discovery (listing, indexing) of this account by external services (search bots etc.) is allowed."
|
||||
},
|
||||
actor_type: ActorType
|
||||
actor_type: ActorType,
|
||||
status_ttl_days: %Schema{
|
||||
type: :integer,
|
||||
nullable: true,
|
||||
description:
|
||||
"Number of days after which statuses will be deleted. Set to -1 to disable."
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
bot: false,
|
||||
|
@ -720,7 +726,8 @@ defp update_credentials_request do
|
|||
allow_following_move: false,
|
||||
also_known_as: ["https://foo.bar/users/foo"],
|
||||
discoverable: false,
|
||||
actor_type: "Person"
|
||||
actor_type: "Person",
|
||||
status_ttl_days: 30
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -109,6 +109,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
|
|||
}
|
||||
}
|
||||
},
|
||||
akkoma: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
note_ttl_days: %Schema{type: :integer}
|
||||
}
|
||||
},
|
||||
source: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
|
|
|
@ -175,6 +175,11 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
|||
value -> {:ok, value}
|
||||
end
|
||||
|
||||
status_ttl_days_value = fn
|
||||
-1 -> {:ok, nil}
|
||||
value -> {:ok, value}
|
||||
end
|
||||
|
||||
user_params =
|
||||
[
|
||||
:no_rich_text,
|
||||
|
@ -215,7 +220,9 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
|||
# Note: param name is indeed :discoverable (not an error)
|
||||
|> Maps.put_if_present(:is_discoverable, params[:discoverable])
|
||||
|> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language]))
|
||||
|> Maps.put_if_present(:status_ttl_days, params[:status_ttl_days], status_ttl_days_value)
|
||||
|
||||
IO.inspect(user_params)
|
||||
# What happens here:
|
||||
#
|
||||
# We want to update the user through the pipeline, but the ActivityPub
|
||||
|
|
|
@ -171,6 +171,16 @@ def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn,
|
|||
Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
|
||||
|> put_application(conn)
|
||||
|
||||
expires_in_seconds =
|
||||
if is_nil(user.status_ttl_days),
|
||||
do: nil,
|
||||
else: 60 * 60 * 24 * user.status_ttl_days
|
||||
|
||||
params =
|
||||
if is_nil(expires_in_seconds),
|
||||
do: params,
|
||||
else: Map.put(params, :expires_in, expires_in_seconds)
|
||||
|
||||
with {:ok, activity} <- CommonAPI.post(user, params) do
|
||||
try_render(conn, "show.json",
|
||||
activity: activity,
|
||||
|
|
|
@ -287,7 +287,8 @@ defp do_render("show.json", %{user: user} = opts) do
|
|||
},
|
||||
last_status_at: user.last_status_at,
|
||||
akkoma: %{
|
||||
instance: render("instance.json", %{instance: instance})
|
||||
instance: render("instance.json", %{instance: instance}),
|
||||
status_ttl_days: user.status_ttl_days
|
||||
},
|
||||
# Pleroma extensions
|
||||
# Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub
|
||||
|
|
|
@ -65,7 +65,7 @@ defp get_replied_to_activities(activities) do
|
|||
# This should be removed in a future version of Pleroma. Pleroma-FE currently
|
||||
# depends on this field, as well.
|
||||
defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do
|
||||
use Bitwise
|
||||
import Bitwise
|
||||
|
||||
:erlang.crc32(context)
|
||||
|> band(bnot(0x8000_0000))
|
||||
|
|
|
@ -14,14 +14,14 @@ def change do
|
|||
from(u in User,
|
||||
where: u.local == true,
|
||||
where: is_nil(u.keys),
|
||||
select: u
|
||||
select: u.id
|
||||
)
|
||||
|
||||
Repo.stream(query)
|
||||
|> Enum.each(fn user ->
|
||||
with {:ok, pem} <- Keys.generate_rsa_pem() do
|
||||
Ecto.Changeset.cast(user, %{keys: pem}, [:keys])
|
||||
|> Repo.update()
|
||||
Ecto.Changeset.cast(%User{id: user}, %{keys: pem}, [:keys])
|
||||
|> Repo.update(returning: false)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddPerUserPostExpiry do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:users) do
|
||||
add(:status_ttl_days, :integer, null: true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -126,6 +126,35 @@ test "posting a status", %{conn: conn} do
|
|||
)
|
||||
end
|
||||
|
||||
test "automatically setting a post expiry if status_ttl_days is set" do
|
||||
user = insert(:user, status_ttl_days: 1)
|
||||
%{user: _user, token: _token, conn: conn} = oauth_access(["write:statuses"], user: user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("api/v1/statuses", %{
|
||||
"status" => "aa chikichiki banban"
|
||||
})
|
||||
|
||||
assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
|
||||
|
||||
activity = Activity.get_by_id_with_object(id)
|
||||
{:ok, expires_at, _} = DateTime.from_iso8601(activity.data["expires_at"])
|
||||
|
||||
assert Timex.diff(
|
||||
expires_at,
|
||||
DateTime.utc_now(),
|
||||
:hours
|
||||
) == 23
|
||||
|
||||
assert_enqueued(
|
||||
worker: Pleroma.Workers.PurgeExpiredActivity,
|
||||
args: %{activity_id: id},
|
||||
scheduled_at: DateTime.add(DateTime.utc_now(), 1 * 60 * 60 * 24)
|
||||
)
|
||||
end
|
||||
|
||||
test "it fails to create a status if `expires_in` is less or equal than an hour", %{
|
||||
conn: conn
|
||||
} do
|
||||
|
|
|
@ -209,6 +209,26 @@ test "updates the user's name", %{conn: conn} do
|
|||
assert update_activity.data["object"]["name"] == "markorepairs"
|
||||
end
|
||||
|
||||
test "updates the user's default post expiry", %{conn: conn} do
|
||||
conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "1"})
|
||||
|
||||
assert user_data = json_response_and_validate_schema(conn, 200)
|
||||
assert user_data["akkoma"]["status_ttl_days"] == 1
|
||||
end
|
||||
|
||||
test "resets the user's default post expiry", %{conn: conn} do
|
||||
conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "-1"})
|
||||
|
||||
assert user_data = json_response_and_validate_schema(conn, 200)
|
||||
assert is_nil(user_data["akkoma"]["status_ttl_days"])
|
||||
end
|
||||
|
||||
test "does not allow negative integers other than -1 for TTL", %{conn: conn} do
|
||||
conn = patch(conn, "/api/v1/accounts/update_credentials", %{"status_ttl_days" => "-2"})
|
||||
|
||||
assert user_data = json_response_and_validate_schema(conn, 403)
|
||||
end
|
||||
|
||||
test "updates the user's AKAs", %{conn: conn} do
|
||||
conn =
|
||||
patch(conn, "/api/v1/accounts/update_credentials", %{
|
||||
|
|
|
@ -37,7 +37,8 @@ test "Represent a user account" do
|
|||
inserted_at: ~N[2017-08-15 15:47:06.597036],
|
||||
emoji: %{"karjalanpiirakka" => "/file.png"},
|
||||
raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"",
|
||||
also_known_as: ["https://shitposter.zone/users/shp"]
|
||||
also_known_as: ["https://shitposter.zone/users/shp"],
|
||||
status_ttl_days: 5
|
||||
})
|
||||
|
||||
insert(:instance, %{host: "example.com", nodeinfo: %{version: "2.1"}})
|
||||
|
@ -61,7 +62,8 @@ test "Represent a user account" do
|
|||
"version" => "2.1"
|
||||
},
|
||||
favicon: nil
|
||||
}
|
||||
},
|
||||
status_ttl_days: 5
|
||||
},
|
||||
avatar: "http://localhost:4001/images/avi.png",
|
||||
avatar_static: "http://localhost:4001/images/avi.png",
|
||||
|
@ -243,7 +245,8 @@ test "Represent a Service(bot) account" do
|
|||
name: "localhost",
|
||||
favicon: "http://localhost:4001/favicon.png",
|
||||
nodeinfo: %{version: "2.0"}
|
||||
}
|
||||
},
|
||||
status_ttl_days: nil
|
||||
},
|
||||
pleroma: %{
|
||||
ap_id: user.ap_id,
|
||||
|
|
Loading…
Reference in a new issue