Compare commits

...

47 commits

Author SHA1 Message Date
marcin mikołajczak
53416190a9 Allow to bite users
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
Signed-off-by: limepotato <limepot@protonmail.ch>
2024-09-02 17:41:11 -06:00
Floatingghost
050bc74437 Merge branch 'develop' into stable 2024-05-22 19:42:46 +01:00
Floatingghost
c02e3432d9 Merge branch 'develop' into stable 2024-04-27 15:11:04 +01:00
Floatingghost
f614bf2725 Merge branch 'develop' into stable 2024-04-27 15:08:35 +01:00
FloatingGhost
26a91d5c9e Merge branch 'develop' into stable 2024-04-02 14:49:23 +01:00
FloatingGhost
d71d52302c Merge branch 'develop' into stable 2024-03-30 13:00:13 +00:00
FloatingGhost
11c305b64b Merge branch 'develop' into stable 2024-03-30 11:45:18 +00:00
FloatingGhost
14515d8d4a Merge branch 'develop' into stable 2024-03-30 11:44:44 +00:00
FloatingGhost
a03f3a9d89 Merge branch 'develop' into stable 2024-02-24 13:57:20 +00:00
floatingghost
ebfb617b26 Update .woodpecker/build-amd64.yml 2023-08-26 13:41:52 +00:00
FloatingGhost
0af8e93135 bump version 2023-08-16 10:44:57 +01:00
FloatingGhost
98a64ab145 Mix format 2023-08-16 00:35:08 +01:00
FloatingGhost
94d1af2c4c Disallow nil hosts in should_federate 2023-08-16 00:34:59 +01:00
FloatingGhost
43c5fd5db0 bullseye build (you owe me for this one) 2023-08-08 22:43:24 +01:00
FloatingGhost
c887dd4f2e Merge branch 'develop' into stable 2023-08-06 15:13:13 +01:00
FloatingGhost
ba1ed37edf Merge branch 'develop' into stable 2023-08-05 14:12:59 +01:00
FloatingGhost
f1de9bd9ba Merge branch 'develop' into stable 2023-08-05 13:37:21 +01:00
FloatingGhost
a4bab7bdfa Merge branch 'develop' into stable 2023-08-05 13:36:43 +01:00
FloatingGhost
a7dbca885f Merge branch 'develop' into stable 2023-08-05 13:26:54 +01:00
FloatingGhost
9d7c877de0 Merge branch 'develop' into stable 2023-05-26 20:46:56 +01:00
FloatingGhost
39a878f530 Merge branch 'develop' into stable 2023-05-26 12:07:05 +01:00
FloatingGhost
dcee1b109b Merge branch 'develop' into stable 2023-05-26 12:05:11 +01:00
FloatingGhost
9a8373a3f5 Merge branch 'develop' into stable 2023-05-23 14:10:19 +01:00
FloatingGhost
ccae7ef824 Merge branch 'develop' into stable 2023-04-14 18:10:07 +01:00
FloatingGhost
8504878187 Merge branch 'develop' into stable 2023-04-14 18:09:32 +01:00
FloatingGhost
fef4bae006 Merge branch 'develop' into stable 2023-03-11 18:25:07 +00:00
FloatingGhost
86dcf273c5 Merge branch 'develop' into stable 2023-03-11 17:26:58 +00:00
FloatingGhost
36cb19dbf2 Merge branch 'develop' into stable 2023-02-15 22:13:30 +00:00
FloatingGhost
71d08991ea Merge branch 'develop' into stable 2023-02-11 11:19:42 +00:00
FloatingGhost
d756607112 Merge branch 'develop' into stable 2023-02-11 10:59:04 +00:00
FloatingGhost
367bc9c818 Merge branch 'develop' into stable 2023-02-11 10:57:01 +00:00
FloatingGhost
81caf77223 Merge branch 'develop' into stable 2023-02-11 10:49:01 +00:00
FloatingGhost
551f92dd50 Merge branch 'develop' into stable 2023-02-11 10:43:22 +00:00
floatingghost
d9508474b6 Merge pull request 'clean-up docs to avoid version-mismatches in BE and FE in new installs (for stable)' (#378) from stefan230/akkoma:stable into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/378
2022-12-19 10:59:34 +00:00
Stefan
f676007b18 clean-up docs to avoid mismatches in BE and FE. Clearly state that stable-versions are installed 2022-12-16 17:23:31 +01:00
FloatingGhost
63f2d1cbef Merge branch 'develop' into stable 2022-12-10 14:50:35 +00:00
FloatingGhost
f91b896731 Merge branch 'develop' into stable 2022-11-12 15:34:19 +00:00
FloatingGhost
af90a4e51b Merge branch 'develop' into stable 2022-10-14 12:49:46 +01:00
FloatingGhost
5e7be063c7 Merge branch 'develop' into stable 2022-10-08 12:12:52 +01:00
FloatingGhost
a1317bf541 use on-release tag 2022-09-20 13:36:28 +01:00
FloatingGhost
a0dd670e68 ensure we use the same OTP for all releases 2022-09-20 13:34:50 +01:00
floatingghost
11d29d27b8 Ensure migrations succeed (#216)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/216
2022-09-16 12:53:45 +01:00
FloatingGhost
44da806a77 Merge branch 'develop' into stable 2022-09-10 17:13:49 +01:00
floatingghost
d7c805b0bb Merge pull request '2022.09 stable' (#208) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/208
2022-09-10 16:06:18 +00:00
floatingghost
c52982e9c5 add finch outbound proxy support (#158)
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/158
2022-08-24 16:03:17 +01:00
floatingghost
2e433e106f generate-keys-at-registration-time (#181)
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/181
2022-08-24 15:39:30 +01:00
floatingghost
bfbe4e8dce Merge pull request 'stable release' (#160) from develop into stable
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/160
2022-08-12 15:25:01 +00:00
22 changed files with 369 additions and 36 deletions

View file

@ -76,6 +76,7 @@ pipeline:
- *clean - *clean
- echo "import Config" > config/prod.secret.exs - echo "import Config" > config/prod.secret.exs
- *setup-hex - *setup-hex
- *mix-clean
- *tag-build - *tag-build
- mix deps.get --only prod - mix deps.get --only prod
- mix release --path release - mix release --path release

View file

@ -339,6 +339,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 2022.08 ## 2022.08
### Removed
- Non-finch HTTP adapters. `:tesla, :adapter` is now highly recommended to be set to the default.
## 2022.08
### Added ### Added
- extended runtime module support, see config cheatsheet - extended runtime module support, see config cheatsheet
- quote posting; quotes are limited to public posts - quote posting; quotes are limited to public posts

View file

@ -72,6 +72,7 @@ defmodule Pleroma.Notification do
pleroma:report pleroma:report
reblog reblog
poll poll
bite
} }
def changeset(%Notification{} = notification, attrs) do def changeset(%Notification{} = notification, attrs) do
@ -402,7 +403,7 @@ defmodule Pleroma.Notification do
end end
def create_notifications(%Activity{data: %{"type" => type}} = activity, options) def create_notifications(%Activity{data: %{"type" => type}} = activity, options)
when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "Update"] do when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "Update", "Bite"] do
do_create_notifications(activity, options) do_create_notifications(activity, options)
end end
@ -459,6 +460,9 @@ defmodule Pleroma.Notification do
"Update" -> "Update" ->
"update" "update"
"Bite" ->
"bite"
t -> t ->
raise "No notification type for activity type #{t}" raise "No notification type for activity type #{t}"
end end
@ -532,7 +536,8 @@ defmodule Pleroma.Notification do
"Move", "Move",
"EmojiReact", "EmojiReact",
"Flag", "Flag",
"Update" "Update",
"Bite"
] do ] do
potential_receiver_ap_ids = get_potential_receiver_ap_ids(activity) potential_receiver_ap_ids = get_potential_receiver_ap_ids(activity)

View file

@ -406,4 +406,15 @@ defmodule Pleroma.Web.ActivityPub.Builder do
defp pinned_url(nickname) when is_binary(nickname) do defp pinned_url(nickname) when is_binary(nickname) do
url(~p[/users/#{nickname}/collections/featured]) url(~p[/users/#{nickname}/collections/featured])
end end
def bite(%User{} = biting, %User{} = bitten) do
{:ok,
%{
"id" => Utils.generate_activity_id(),
"target" => bitten.ap_id,
"actor" => biting.ap_id,
"type" => "Bite",
"to" => [bitten.ap_id]
}, []}
end
end end

View file

@ -22,6 +22,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BiteValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator alias Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator alias Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator
@ -160,7 +161,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
def validate(%{"type" => type} = object, meta) def validate(%{"type" => type} = object, meta)
when type in ~w[Accept Reject Follow Update Like EmojiReact Announce when type in ~w[Accept Reject Follow Update Like EmojiReact Announce
Answer] do Answer Bite] do
validator = validator =
case type do case type do
"Accept" -> AcceptRejectValidator "Accept" -> AcceptRejectValidator
@ -171,6 +172,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"EmojiReact" -> EmojiReactValidator "EmojiReact" -> EmojiReactValidator
"Announce" -> AnnounceValidator "Announce" -> AnnounceValidator
"Answer" -> AnswerValidator "Answer" -> AnswerValidator
"Bite" -> BiteValidator
end end
with {:ok, object} <- with {:ok, object} <-

View file

@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|> validate_required([:type, :actor, :to, :cc, :object]) |> validate_required([:type, :actor, :to, :cc, :object])
|> validate_inclusion(:type, ["Accept", "Reject"]) |> validate_inclusion(:type, ["Accept", "Reject"])
|> validate_actor_presence() |> validate_actor_presence()
|> validate_object_presence(allowed_types: ["Follow"]) |> validate_object_presence(allowed_types: ["Follow", "Bite"])
|> validate_accept_reject_rights() |> validate_accept_reject_rights()
end end
@ -46,8 +46,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
def validate_accept_reject_rights(cng) do def validate_accept_reject_rights(cng) do
with object_id when is_binary(object_id) <- get_field(cng, :object), with object_id when is_binary(object_id) <- get_field(cng, :object),
%Activity{data: %{"object" => followed_actor}} <- Activity.get_by_ap_id(object_id), %Activity{} = activity <- Activity.get_by_ap_id(object_id),
true <- followed_actor == get_field(cng, :actor) do true <- validate_actor(activity, get_field(cng, :actor)) do
cng cng
else else
_e -> _e ->
@ -56,6 +56,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
end end
end end
defp validate_actor(%Activity{data: %{"type" => "Follow", "object" => followed_actor}}, actor) do
followed_actor == actor
end
defp validate_actor(%Activity{data: %{"type" => "Bite", "target" => biten_actor}}, actor) do
biten_actor == actor
end
defp maybe_fetch_object(%{"object" => %{} = object} = activity) do defp maybe_fetch_object(%{"object" => %{} = object} = activity) do
# If we don't have an ID, we may have to fetch the object # If we don't have an ID, we may have to fetch the object
if Map.has_key?(object, "id") do if Map.has_key?(object, "id") do

View file

@ -0,0 +1,49 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.BiteValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@primary_key false
embedded_schema do
quote do
unquote do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
end
end
field(:target, ObjectValidators.ObjectID)
end
def cast_data(data) do
%__MODULE__{}
|> cast(data |> fix_object(), __schema__(:fields))
end
defp fix_object(data) do
Map.put(data, "object", data["target"])
end
defp validate_data(cng) do
cng
|> validate_required([:id, :type, :actor, :to, :target])
|> validate_inclusion(:type, ["Bite"])
|> validate_actor_presence()
|> validate_actor_presence(field_name: :target)
end
def cast_and_validate(data) do
data
|> cast_data
|> validate_data
end
end

View file

@ -40,23 +40,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
# - Sends a notification # - Sends a notification
@impl true @impl true
def handle( def handle(
%{ %{data: %{"actor" => actor, "type" => "Accept", "object" => activity_id}} = object,
data: %{
"actor" => actor,
"type" => "Accept",
"object" => follow_activity_id
}
} = object,
meta meta
) do ) do
with %Activity{actor: follower_id} = follow_activity <- with %Activity{} = activity <-
Activity.get_by_ap_id(follow_activity_id), Activity.get_by_ap_id(activity_id) do
%User{} = followed <- User.get_cached_by_ap_id(actor), handle_accepted(activity, actor)
%User{} = follower <- User.get_cached_by_ap_id(follower_id),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"), if activity.data["type"] === "Join" do
{:ok, _follower, followed} <- Notification.create_notifications(object)
FollowingRelationship.update(follower, followed, :follow_accept) do end
Notification.update_notification_type(followed, follow_activity)
end end
{:ok, object, meta} {:ok, object, meta}
@ -72,18 +65,14 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
data: %{ data: %{
"actor" => actor, "actor" => actor,
"type" => "Reject", "type" => "Reject",
"object" => follow_activity_id "object" => activity_id
} }
} = object, } = object,
meta meta
) do ) do
with %Activity{actor: follower_id} = follow_activity <- with %Activity{} = activity <-
Activity.get_by_ap_id(follow_activity_id), Activity.get_by_ap_id(activity_id) do
%User{} = followed <- User.get_cached_by_ap_id(actor), handle_rejected(activity, actor)
%User{} = follower <- User.get_cached_by_ap_id(follower_id),
{:ok, _follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject") do
FollowingRelationship.update(follower, followed, :follow_reject)
Notification.dismiss(follow_activity)
end end
{:ok, object, meta} {:ok, object, meta}
@ -397,12 +386,93 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end end
end end
# Task this handles
# - Bites
# - Sends a notification
@impl true
def handle(
%{
data: %{
"id" => bite_id,
"type" => "Bite",
"target" => bitten_user,
"actor" => biting_user
}
} = object,
meta
) do
with %User{} = biting <- User.get_cached_by_ap_id(biting_user),
%User{} = bitten <- User.get_cached_by_ap_id(bitten_user),
{:previous_bite, previous_bite} <-
{:previous_bite, Utils.fetch_latest_bite(biting, bitten, object)},
{:reverse_bite, reverse_bite} <-
{:reverse_bite, Utils.fetch_latest_bite(bitten, biting)},
{:can_bite, true, _} <- {:can_bite, can_bite?(previous_bite, reverse_bite), bitten} do
if bitten.local do
{:ok, accept_data, _} = Builder.accept(bitten, object)
{:ok, _activity, _} = Pipeline.common_pipeline(accept_data, local: true)
end
if reverse_bite do
Notification.dismiss(reverse_bite)
end
{:ok, notifications} = Notification.create_notifications(object)
meta
|> add_notifications(notifications)
else
{:can_bite, false, bitten} ->
{:ok, reject_data, _} = Builder.reject(bitten, object)
{:ok, _activity, _} = Pipeline.common_pipeline(reject_data, local: true)
meta
_ ->
meta
end
updated_object = Activity.get_by_ap_id(bite_id)
{:ok, updated_object, meta}
end
# Nothing to do # Nothing to do
@impl true @impl true
def handle(object, meta) do def handle(object, meta) do
{:ok, object, meta} {:ok, object, meta}
end end
defp handle_accepted(
%Activity{actor: follower_id, data: %{"type" => "Follow"}} = follow_activity,
actor
) do
with %User{} = followed <- User.get_cached_by_ap_id(actor),
%User{} = follower <- User.get_cached_by_ap_id(follower_id),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
{:ok, _follower, followed} <-
FollowingRelationship.update(follower, followed, :follow_accept) do
Notification.update_notification_type(followed, follow_activity)
end
end
defp handle_accepted(_, _), do: nil
defp handle_rejected(
%Activity{actor: follower_id, data: %{"type" => "Follow"}} = follow_activity,
actor
) do
with %User{} = followed <- User.get_cached_by_ap_id(actor),
%User{} = follower <- User.get_cached_by_ap_id(follower_id),
{:ok, _follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject") do
FollowingRelationship.update(follower, followed, :follow_reject)
Notification.dismiss(follow_activity)
end
end
defp handle_rejected(%Activity{data: %{"type" => "Bite"}} = bite_activity, _actor) do
Notification.dismiss(bite_activity)
end
defp handle_update_user( defp handle_update_user(
%{data: %{"type" => "Update", "object" => updated_object}} = object, %{data: %{"type" => "Update", "object" => updated_object}} = object,
meta meta
@ -587,4 +657,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|> send_notifications() |> send_notifications()
|> send_streamables() |> send_streamables()
end end
defp can_bite?(nil, _), do: true
defp can_bite?(_, nil), do: false
defp can_bite?(previous_bite, reverse_bite) do
NaiveDateTime.diff(previous_bite.inserted_at, reverse_bite.inserted_at) < 0
end
end end

View file

@ -519,7 +519,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end end
defp handle_incoming_normalised(%{"type" => type} = data, _options) defp handle_incoming_normalised(%{"type" => type} = data, _options)
when type in ~w{Like EmojiReact Announce Add Remove} do when type in ~w{Like EmojiReact Announce Add Remove Bite} do
with :ok <- ObjectValidator.fetch_actor_and_object(data), with :ok <- ObjectValidator.fetch_actor_and_object(data),
{:ok, activity, _meta} <- Pipeline.common_pipeline(data, local: false) do {:ok, activity, _meta} <- Pipeline.common_pipeline(data, local: false) do
{:ok, activity} {:ok, activity}
@ -533,7 +533,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => type} = data, %{"type" => type} = data,
_options _options
) )
when type in ~w{Update Block Follow Accept Reject} do when type in ~w{Update Block Follow Accept Reject Bite} do
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data), with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
{:ok, activity, _} <- {:ok, activity, _} <-
Pipeline.common_pipeline(data, local: false) do Pipeline.common_pipeline(data, local: false) do

View file

@ -888,4 +888,36 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> where([a, object: o], fragment("(?)->>'type' = 'Answer'", o.data)) |> where([a, object: o], fragment("(?)->>'type' = 'Answer'", o.data))
|> Repo.all() |> Repo.all()
end end
def make_bite_data(biting, bitten, activity_id) do
%{
"type" => "Bite",
"actor" => biting.ap_id,
"to" => [bitten.ap_id],
"target" => bitten.ap_id
}
|> Maps.put_if_present("id", activity_id)
end
def fetch_latest_bite(
%User{ap_id: biting_ap_id},
%{ap_id: bitten_ap_id},
exclude_activity \\ nil
) do
"Bite"
|> Activity.Queries.by_type()
|> where(actor: ^biting_ap_id)
|> maybe_exclude_activity_id(exclude_activity)
|> Activity.Queries.by_object_id(bitten_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
defp maybe_exclude_activity_id(query, nil), do: query
defp maybe_exclude_activity_id(query, %Activity{id: activity_id}) do
query
|> where([a], a.id != ^activity_id)
end
end end

View file

@ -79,7 +79,7 @@ defmodule Pleroma.Web.ApiSpec do
"x-tagGroups": [ "x-tagGroups": [
%{ %{
"name" => "Accounts", "name" => "Accounts",
"tags" => ["Account actions", "Retrieve account information"] "tags" => ["Account actions", "Bites", "Retrieve account information"]
}, },
%{ %{
"name" => "Administration", "name" => "Administration",

View file

@ -0,0 +1,33 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.BiteOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.ApiError
@spec open_api_operation(atom) :: Operation.t()
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def bite_operation do
%Operation{
tags: ["Bites"],
summary: "Bite",
operationId: "BiteController.bite",
security: [%{"oAuth" => ["write:bites"]}],
description: "Bite the given account",
parameters: [
Operation.parameter(:id, :query, :string, "Bitten account ID")
],
responses: %{
200 => Operation.response("Empty object", "application/json", %Schema{type: :object}),
400 => Operation.response("Error", "application/json", ApiError),
404 => Operation.response("Error", "application/json", ApiError)
}
}
end
end

View file

@ -177,7 +177,8 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
"pleroma:report", "pleroma:report",
"move", "move",
"follow_request", "follow_request",
"poll" "poll",
"bite"
], ],
description: """ description: """
The type of event that resulted in the notification. The type of event that resulted in the notification.
@ -190,6 +191,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
- `move` - Someone moved their account - `move` - Someone moved their account
- `pleroma:emoji_reaction` - Someone reacted with emoji to your status - `pleroma:emoji_reaction` - Someone reacted with emoji to your status
- `pleroma:report` - Someone was reported - `pleroma:report` - Someone was reported
- `bite` - Someone bit you
""" """
} }
end end

View file

@ -578,4 +578,11 @@ defmodule Pleroma.Web.CommonAPI do
nil nil
end end
end end
def bite(biting, bitten) do
with {:ok, bite_data, _} <- Builder.bite(biting, bitten),
{:ok, activity, _} <- Pipeline.common_pipeline(bite_data, local: true) do
{:ok, biting, bitten, activity}
end
end
end end

View file

@ -0,0 +1,39 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.BiteController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [assign_account_by_id: 2, json_response: 3]
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Plugs.OAuthScopesPlug
# alias Pleroma.Web.Plugs.RateLimiter
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["write:bite"]} when action == :bite)
# plug(RateLimiter, [name: :relations_actions] when action in @relationship_actions)
# plug(RateLimiter, [name: :app_account_creation] when action == :create)
plug(:assign_account_by_id)
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.BiteOperation
@doc "POST /api/v1/bite"
def bite(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
{:error, "Can not bite yourself"}
end
def bite(%{assigns: %{user: biting, account: bitten}} = conn, _) do
with {:ok, _, _, _} <- CommonAPI.bite(biting, bitten) do
json_response(conn, :ok, %{})
else
{:error, message} -> json_response(conn, :forbidden, %{error: message})
end
end
end

View file

@ -52,6 +52,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
pleroma:emoji_reaction pleroma:emoji_reaction
poll poll
update update
bite
} }
def index(%{assigns: %{user: user}} = conn, params) do def index(%{assigns: %{user: user}} = conn, params) do
params = params =

View file

@ -90,7 +90,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"akkoma:machine_translation" "akkoma:machine_translation"
end, end,
"custom_emoji_reactions", "custom_emoji_reactions",
"pleroma:get:main/ostatus" "pleroma:get:main/ostatus",
"pleroma:bites"
] ]
|> Enum.filter(& &1) |> Enum.filter(& &1)
end end

View file

@ -128,7 +128,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
"pleroma:report" -> "pleroma:report" ->
put_report(response, activity) put_report(response, activity)
type when type in ["follow", "follow_request"] -> type when type in ["follow", "follow_request", "bite"] ->
response response
end end
end end

View file

@ -80,6 +80,10 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do
bubble: !Config.restrict_unauthenticated_access?(:timelines, :bubble) bubble: !Config.restrict_unauthenticated_access?(:timelines, :bubble)
}, },
federatedTimelineAvailable: Config.get([:instance, :federated_timeline_available], true) federatedTimelineAvailable: Config.get([:instance, :federated_timeline_available], true)
},
operations: %{
"com.shinolabs.api.bite": ["1.0.0"],
"jetzt.mia.ns.activitypub.accept.bite": ["1.0.0"]
} }
} }
end end

View file

@ -631,6 +631,8 @@ defmodule Pleroma.Web.Router do
get("/followed_tags", TagController, :show_followed) get("/followed_tags", TagController, :show_followed)
get("/preferences", AccountController, :preferences) get("/preferences", AccountController, :preferences)
post("/bite", BiteController, :bite)
end end
scope "/api/web", Pleroma.Web do scope "/api/web", Pleroma.Web do

View file

@ -0,0 +1,52 @@
defmodule Pleroma.Repo.Migrations.AddBiteToNotificationsEnum do
use Ecto.Migration
@disable_ddl_transaction true
def up do
"""
alter type notification_type add value 'bite'
"""
|> execute()
end
# 20220605185734_add_update_to_notifications_enum.exs
def down do
alter table(:notifications) do
modify(:type, :string)
end
"""
delete from notifications where type = 'bite'
"""
|> execute()
"""
drop type if exists notification_type
"""
|> execute()
"""
create type notification_type as enum (
'follow',
'follow_request',
'mention',
'move',
'pleroma:emoji_reaction',
'pleroma:chat_mention',
'reblog',
'favourite',
'pleroma:report',
'poll',
'update'
)
"""
|> execute()
"""
alter table notifications
alter column type type notification_type using (type::notification_type)
"""
|> execute()
end
end

View file

@ -54,7 +54,8 @@
"backgroundUrl": { "backgroundUrl": {
"@id": "sharkey:backgroundUrl", "@id": "sharkey:backgroundUrl",
"@type": "@id" "@type": "@id"
} },
"Bite": "https://ns.mia.jetzt/as#Bite"
} }
] ]
} }