Browse Source

Add support for activity expiration to common and Masto API

The "expires_at" parameter accepts an ISO8601-formatted date which
defines when the activity will expire.

At this point the API will not give you any feedback about if your post
will expire or not.
tags/v1.1.4
Mike Verdone 4 years ago
parent
commit
704960b3c1
6 changed files with 82 additions and 13 deletions
  1. +1
    -0
      docs/api/differences_in_mastoapi_responses.md
  2. +19
    -0
      lib/pleroma/activity_expiration.ex
  3. +20
    -9
      lib/pleroma/web/common_api/common_api.ex
  4. +6
    -4
      test/support/factory.ex
  5. +17
    -0
      test/web/common_api/common_api_test.exs
  6. +19
    -0
      test/web/mastodon_api/mastodon_api_controller_test.exs

+ 1
- 0
docs/api/differences_in_mastoapi_responses.md View File

@@ -79,6 +79,7 @@ Additional parameters can be added to the JSON body/Form data:
- `content_type`: string, contain the MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint.
- `to`: A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply.
- `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`.
- `expires_on`: datetime (iso8601), sets when the posted activity should expire. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated.

## PATCH `/api/v1/update_credentials`



+ 19
- 0
lib/pleroma/activity_expiration.ex View File

@@ -10,6 +10,7 @@ defmodule Pleroma.ActivityExpiration do
alias Pleroma.FlakeId
alias Pleroma.Repo

import Ecto.Changeset
import Ecto.Query

@type t :: %__MODULE__{}
@@ -19,6 +20,24 @@ defmodule Pleroma.ActivityExpiration do
field(:scheduled_at, :naive_datetime)
end

def changeset(%ActivityExpiration{} = expiration, attrs) do
expiration
|> cast(attrs, [:scheduled_at])
|> validate_required([:scheduled_at])
end

def get_by_activity_id(activity_id) do
ActivityExpiration
|> where([exp], exp.activity_id == ^activity_id)
|> Repo.one()
end

def create(%Activity{} = activity, scheduled_at) do
%ActivityExpiration{activity_id: activity.id}
|> changeset(%{scheduled_at: scheduled_at})
|> Repo.insert()
end

def due_expirations(offset \\ 0) do
naive_datetime =
NaiveDateTime.utc_now()


+ 20
- 9
lib/pleroma/web/common_api/common_api.ex View File

@@ -4,6 +4,7 @@

defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity
alias Pleroma.ActivityExpiration
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.ThreadMute
@@ -218,6 +219,7 @@ defmodule Pleroma.Web.CommonAPI do
context <- make_context(in_reply_to),
cw <- data["spoiler_text"] || "",
sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
{:ok, expires_at} <- Ecto.Type.cast(:naive_datetime, data["expires_at"]),
full_payload <- String.trim(status <> cw),
:ok <- validate_character_limit(full_payload, attachments, limit),
object <-
@@ -243,15 +245,24 @@ defmodule Pleroma.Web.CommonAPI do
preview? = Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
direct? = visibility == "direct"

%{
to: to,
actor: user,
context: context,
object: object,
additional: %{"cc" => cc, "directMessage" => direct?}
}
|> maybe_add_list_data(user, visibility)
|> ActivityPub.create(preview?)
result =
%{
to: to,
actor: user,
context: context,
object: object,
additional: %{"cc" => cc, "directMessage" => direct?}
}
|> maybe_add_list_data(user, visibility)
|> ActivityPub.create(preview?)

if expires_at do
with {:ok, activity} <- result do
ActivityExpiration.create(activity, expires_at)
end
end

result
else
{:private_to_public, true} ->
{:error, dgettext("errors", "The message visibility must be direct")}


+ 6
- 4
test/support/factory.ex View File

@@ -143,12 +143,14 @@ defmodule Pleroma.Factory do
end

defp expiration_offset_by_minutes(attrs, minutes) do
scheduled_at =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(minutes), :millisecond)
|> NaiveDateTime.truncate(:second)

%Pleroma.ActivityExpiration{}
|> Map.merge(attrs)
|> Map.put(
:scheduled_at,
NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(minutes), :millisecond)
)
|> Map.put(:scheduled_at, scheduled_at)
end

def expiration_in_the_past_factory(attrs \\ %{}) do


+ 17
- 0
test/web/common_api/common_api_test.exs View File

@@ -160,6 +160,23 @@ defmodule Pleroma.Web.CommonAPITest do

Pleroma.Config.put([:instance, :limit], limit)
end

test "it can handle activities that expire" do
user = insert(:user)

expires_at =
NaiveDateTime.utc_now()
|> NaiveDateTime.truncate(:second)
|> NaiveDateTime.add(1_000_000, :second)

expires_at_iso8601 = expires_at |> NaiveDateTime.to_iso8601()

assert {:ok, activity} =
CommonAPI.post(user, %{"status" => "chai", "expires_at" => expires_at_iso8601})

assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id)
assert expiration.scheduled_at == expires_at
end
end

describe "reactions" do


+ 19
- 0
test/web/mastodon_api/mastodon_api_controller_test.exs View File

@@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do

alias Ecto.Changeset
alias Pleroma.Activity
alias Pleroma.ActivityExpiration
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
@@ -151,6 +152,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do

assert %{"id" => third_id} = json_response(conn_three, 200)
refute id == third_id

# An activity that will expire:
expires_at =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(:timer.minutes(120), :millisecond)
|> NaiveDateTime.truncate(:second)

conn_four =
conn
|> post("api/v1/statuses", %{
"status" => "oolong",
"expires_at" => expires_at
})

assert %{"id" => fourth_id} = json_response(conn_four, 200)
assert activity = Activity.get_by_id(fourth_id)
assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
assert expiration.scheduled_at == expires_at
end

test "replying to a status", %{conn: conn} do


Loading…
Cancel
Save