added 'ClosePoll' activity

This commit is contained in:
Maksim Pechnikov 2020-12-07 21:30:37 +03:00
parent ed76323776
commit 572e03c0cc
9 changed files with 148 additions and 6 deletions

View File

@ -553,7 +553,8 @@
remote_fetcher: 2,
attachments_cleanup: 5,
new_users_digest: 1,
mute_expire: 5
mute_expire: 5,
poll_expiration_notify: 1
],
plugins: [Oban.Plugins.Pruner],
crontab: [

View File

@ -368,7 +368,7 @@ def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = act
end
def create_notifications(%Activity{data: %{"type" => type}} = activity, options)
when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag"] do
when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "ClosePoll"] do
do_create_notifications(activity, options)
end
@ -418,9 +418,11 @@ defp type_from_activity(%{data: %{"type" => type}} = activity) do
"EmojiReaction" ->
"pleroma:emoji_reaction"
"ClosePoll" ->
"poll"
"Create" ->
activity
|> type_from_activity_object()
type_from_activity_object(activity)
t ->
raise "No notification type for activity type #{t}"
@ -471,7 +473,16 @@ def create_notification(%Activity{} = activity, %User{} = user, do_send \\ true)
def get_notified_from_activity(activity, local_only \\ true)
def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only)
when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReact", "Flag"] do
when type in [
"Create",
"Like",
"Announce",
"Follow",
"Move",
"EmojiReact",
"Flag",
"ClosePoll"
] do
potential_receiver_ap_ids = get_potential_receiver_ap_ids(activity)
potential_receivers =
@ -511,6 +522,10 @@ def get_potential_receiver_ap_ids(%{data: %{"type" => "Flag"}}) do
User.all_superusers() |> Enum.map(fn user -> user.ap_id end)
end
def get_potential_receiver_ap_ids(%{data: %{"type" => "ClosePoll"}}) do
[]
end
def get_potential_receiver_ap_ids(activity) do
[]
|> Utils.maybe_notify_to_recipients(activity)

View File

@ -65,6 +65,15 @@ def emoji_react(actor, object, emoji) do
end
end
def close_poll(_activity, object) do
{:ok,
%{
"id" => Utils.generate_activity_id(),
"type" => "ClosePoll",
"object" => object.data["id"]
}, []}
end
@spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
def undo(actor, object) do
{:ok,

View File

@ -21,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ClosePollValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
@ -151,6 +152,16 @@ def validate(%{"type" => "Question"} = object, meta) do
end
end
def validate(%{"type" => "ClosePoll"} = object, meta) do
with {:ok, object} <-
object
|> ClosePollValidator.cast_and_validate()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
end
end
def validate(%{"type" => type} = object, meta) when type in ~w[Audio Video] do
with {:ok, object} <-
object

View File

@ -0,0 +1,41 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.ClosePollValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
import Ecto.Changeset
@primary_key false
embedded_schema do
field(:id, ObjectValidators.ObjectID, primary_key: true)
field(:type, :string)
field(:object, ObjectValidators.ObjectID)
end
def cast_and_validate(data) do
data
|> cast_data()
|> validate_data()
end
def cast_data(data) do
%__MODULE__{}
|> changeset(data)
end
def changeset(struct, data) do
struct
|> cast(data, __schema__(:fields))
end
def validate_data(data_cng) do
data_cng
|> validate_inclusion(:type, ["ClosePoll"])
|> validate_required([:id, :type, :object])
end
end

View File

@ -244,6 +244,14 @@ def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
{:ok, object, meta}
end
# Tasks this handles:
# - Set up notification on close poll
def handle(%{data: %{"type" => "ClosePoll"}} = object, meta) do
Notification.create_notifications(object)
{:ok, object, meta}
end
# Tasks this handles:
# - Delete and unpins the create activity
# - Replace object with Tombstone

View File

@ -264,6 +264,18 @@ def unfavorite(id, user) do
end
end
# postprocess the close poll
#
def close_poll(activity_id) do
with %Activity{} = activity <- Activity.get_by_id(activity_id),
%Object{} = object <- Object.normalize(activity),
{:ok, poll, _} <- Builder.close_poll(activity, object),
meta <- [local: true, do_not_federate: true],
{:ok, activity, _} <- Pipeline.common_pipeline(poll, meta) do
{:ok, activity}
end
end
def react_with_emoji(id, user, emoji) do
with %Activity{} = activity <- Activity.get_by_id(id),
object <- Object.normalize(activity),
@ -411,6 +423,25 @@ def post(user, %{status: _} = data) do
end
end
def postprocess(%Activity{} = activity) do
case Object.normalize(activity) do
%Object{data: %{"type" => "Question", "closed" => closed_at}} ->
Pleroma.Workers.PollExpirationNotify.enqueue(%{
activity_id: activity.id,
closed_at:
Timex.shift(
Timex.parse!(closed_at, "{ISO:Extended:Z}"),
minutes: 1
)
})
_ ->
activity
end
activity
end
def pin(id, %{ap_id: user_ap_id} = user) do
with %Activity{
actor: ^user_ap_id,

View File

@ -164,7 +164,8 @@ def create(
def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do
params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
with {:ok, activity} <- CommonAPI.post(user, params) do
with {:ok, activity} <- CommonAPI.post(user, params),
_ <- CommonAPI.postprocess(activity) do
try_render(conn, "show.json",
activity: activity,
for: user,

View File

@ -0,0 +1,25 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.PollExpirationNotify do
@moduledoc false
use Oban.Worker, queue: :poll_expiration_notify, max_attempts: 1
def enqueue(args) do
{scheduled_at, args} = Map.pop(args, :closed_at)
args
|> __MODULE__.new(scheduled_at: scheduled_at)
|> Oban.insert()
end
@impl true
def perform(%Oban.Job{args: %{"activity_id" => activity_id}}) do
Pleroma.Web.CommonAPI.close_poll(activity_id)
:ok
end
def perform(_), do: :ok
end