Skip to content

Commit

Permalink
https://github.com/bonfire-networks/bonfire-app/issues/831
Browse files Browse the repository at this point in the history
  • Loading branch information
mayel committed Jan 25, 2024
1 parent 618de7d commit 5cd4c4f
Show file tree
Hide file tree
Showing 15 changed files with 649 additions and 28 deletions.
1 change: 1 addition & 0 deletions deps.git
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bonfire_common = "https://github.com/bonfire-networks/bonfire_common#main"
bonfire_ui_common = "https://github.com/bonfire-networks/bonfire_ui_common#main"
bonfire_classify = "https://github.com/bonfire-networks/bonfire_classify#main"
7 changes: 0 additions & 7 deletions lib/integration.ex

This file was deleted.

41 changes: 41 additions & 0 deletions lib/label_schema.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule Bonfire.Label do
use Needle.Virtual,
otp_app: :bonfire_label,
table_id: "71ABE1SADDED0NT0S0METH1NGS",
source: "bonfire_label_labelled"

alias Bonfire.Data.Edges.Edge
alias Bonfire.Label
alias Needle.Changesets

virtual_schema do
has_one(:edge, Edge, foreign_key: :id)
end

def changeset(label \\ %Label{}, params),
do: Changesets.cast(label, params, [])
end

defmodule Bonfire.Label.Migration do
@moduledoc false
import Ecto.Migration
import Needle.Migration
import Bonfire.Data.Edges.EdgeTotal.Migration
alias Bonfire.Label

def migrate_label_view(), do: migrate_virtual(Label)

# def migrate_label_total_view(), do: migrate_edge_total_view(Label)

def migrate_label(dir \\ direction())

def migrate_label(:up) do
migrate_label_view()
# migrate_label_total_view()
end

def migrate_label(:down) do
# migrate_label_total_view()
migrate_label_view()
end
end
216 changes: 216 additions & 0 deletions lib/labelling.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
defmodule Bonfire.Label.Labelling do
# alias Bonfire.Data.Identity.User
alias Bonfire.Label
# alias Bonfire.Boundaries.Verbs

alias Bonfire.Social.Activities
alias Bonfire.Social.Edges
alias Bonfire.Social.Feeds
# alias Bonfire.Social.FeedActivities
alias Bonfire.Social.Integration
alias Bonfire.Social.LivePush
alias Bonfire.Social.Objects

# alias Bonfire.Data.Edges.Edge

use Bonfire.Common.Repo,
searchable_fields: [:labeler_id, :labelled_id]

# import Bonfire.Social.Integration
use Bonfire.Common.Utils

@behaviour Bonfire.Common.QueryModule
@behaviour Bonfire.Common.ContextModule
def schema_module, do: Label
def query_module, do: __MODULE__

def labelled?(%{} = user, object),
do: Edges.exists?(__MODULE__, user, object, skip_boundary_check: true)

def count(filters \\ [], opts \\ [])

def count(filters, opts) when is_list(filters) and is_list(opts) do
Edges.count(__MODULE__, filters, opts)
end

def count(%{} = user, object) when is_struct(object) or is_binary(object),
do: Edges.count_for_subject(__MODULE__, user, object, skip_boundary_check: true)

def count(object, _) when is_struct(object),
do: Edges.count(:label, object, skip_boundary_check: true)

def date_last_labelled(%{} = user, object),
do: Edges.last_date(__MODULE__, user, object, skip_boundary_check: true)

def get(subject, object, opts \\ []),
do: Edges.get(__MODULE__, subject, object, opts)

def get!(subject, object, opts \\ []),
do: Edges.get!(__MODULE__, subject, object, opts)

def label(labeler, labelled, opts \\ [])

def label(%{} = labeler, %{} = object, opts) do
# if Bonfire.Boundaries.can?(labeler, :label, object) do
do_label(labeler, object, opts)
# else
# error(l("Sorry, you cannot label this"))
# end
end

def label(%{} = labeler, labelled, opts) when is_binary(labelled) do
with {:ok, object} <-
Bonfire.Common.Needles.get(
labelled,
opts ++
[
current_user: labeler,
# verbs: [:label]
verbs: [:read]
]
) do
# debug(liked)
do_label(labeler, object, opts)
else
_ ->
error(l("Sorry, you cannot label this"))
end
end

def label(labelers, object, opts) when is_list(labelers) do
labelers
|> Enum.each(&label(&1, object, opts))
end

defp do_label(%{} = labeler, %{} = labelled, opts \\ []) do
labelled = Objects.preload_creator(labelled)
labelled_creator = Objects.object_creator(labelled)

opts = [
# TODO: get the preset for labeling from config and/or user's settings
boundary: "public",
to_circles: [id(labelled_creator)],
to_feeds:
[outbox: labeler] ++
if(e(opts, :notify_creator, true),
do: Feeds.maybe_creator_notification(labeler, labelled_creator, opts),
else: []
)
]

with {:ok, label} <- create(labeler, labelled, opts) do
# livepush will need a list of feed IDs we published to
feed_ids = for fp <- label.feed_publishes, do: fp.feed_id

LivePush.push_activity_object(feed_ids, label, labelled,
push_to_thread: false,
notify: true
)

Integration.maybe_federate_and_gift_wrap_activity(labeler, label)
|> debug("maybe_federated the label")
end
end

def unlabel(labeler, labelled, opts \\ [])

def unlabel(labeler, %{} = labelled, _opts) do
# delete the Label
Edges.delete_by_both(labeler, Label, labelled)
# delete the label activity & feed entries
{:ok, Activities.delete_by_subject_verb_object(labeler, :label, labelled)}
end

def unlabel(labeler, labelled, opts) when is_binary(labelled) do
with {:ok, labelled} <-
Bonfire.Common.Needles.get(labelled, opts ++ [current_user: labeler]) do
# debug(liked)
unlabel(labeler, labelled)
end
end

@doc "List current user's labels"
def list_my(opts) do
list_by(current_user_required!(opts), opts)
end

@doc "List labels by the user "
def list_by(by_user, opts \\ [])
when is_binary(by_user) or is_list(by_user) or is_map(by_user) do
# query FeedPublish
# [preload: [object: [created: [:creator]]]])
list_paginated(
[subject: by_user],
to_options(opts) ++ [preload: :object_with_creator, subject_user: by_user]
)
end

@doc "List label of an object"
def list_of(id, opts \\ []) when is_binary(id) or is_list(id) or is_map(id) do
opts = to_options(opts)
# query FeedPublish
list_paginated([object: id], opts ++ [preload: :subject])
end

def list_paginated(filters, opts \\ []) do
filters
|> query(opts)
# |> debug()
|> repo().many_paginated(opts)

# TODO: activity preloads
end

defp query_base(filters, opts) do
Edges.query_parent(Label, filters, opts)

# |> proload(edge: [
# # subject: {"labeler_", [:profile, :character]},
# # object: {"labelled_", [:profile, :character, :post_content]}
# ])
# |> query_filter(filters)
end

def query([my: :labels], opts),
do: query([subject: current_user_required!(opts)], opts)

def query(filters, opts) do
query_base(filters, opts)
end

defp create(labeler, labelled, opts) do
Edges.insert(Label, labeler, :label, labelled, opts)
end

def ap_publish_activity(subject, :delete, label) do
with {:ok, labeler} <-
ActivityPub.Actor.get_cached(
pointer: subject || e(label.edge, :subject, nil) || e(label.edge, :subject_id, nil)
),
{:ok, object} <-
ActivityPub.Object.get_cached(
pointer: e(label.edge, :object, nil) || e(label.edge, :object_id, nil)
) do
ActivityPub.unannounce(%{actor: labeler, object: object})
end
end

def ap_publish_activity(subject, _verb, label) do
label = repo().maybe_preload(label, :edge)

with {:ok, labeler} <-
ActivityPub.Actor.get_cached(
pointer:
subject || e(label, :edge, :subject, nil) || e(label, :edge, :subject_id, nil)
),
{:ok, object} <-
ActivityPub.Object.get_cached(
pointer: e(label, :edge, :object, nil) || e(label, :edge, :object_id, nil)
) do
ActivityPub.announce(%{actor: labeler, object: object, pointer: ulid(label)})
else
e ->
error(e, "Could not find the federated actor or object to label.")
end
end
end
35 changes: 35 additions & 0 deletions lib/labels.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Bonfire.Label.Labels do
alias Bonfire.Common.Config
alias Bonfire.Common.Utils
# import Untangle

def top_label_id, do: "7CATEG0RYTHATC0NTA1N1ABE1S"

def repo, do: Config.repo()

def get(id, name, opts \\ []) do
Bonfire.Classify.Categories.get(id, opts ++ [skip_boundary_check: true])
end

def get_or_create(id, name, parent_id \\ nil, username \\ nil) do
with {:error, :not_found} <-
get(id, [
# :default_incl_deleted,
# current_user: current_user
]) do
create(id, name, parent_id, username)
end
end

def create(id, name, parent_id \\ nil, username \\ nil) do
Bonfire.Classify.Categories.create(nil, %{
id: id,
name: name,
type: :label,
parent_category:
parent_id || if(id != top_label_id(), do: get_or_create(top_label_id(), "Labels")),
username: username,
without_character: !username
})
end
end
4 changes: 0 additions & 4 deletions lib/migrations.ex

This file was deleted.

42 changes: 39 additions & 3 deletions lib/web/components/content_label_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,47 @@ defmodule Bonfire.Label.Web.ContentLabelLive do
use Bonfire.UI.Common.Web, :stateless_component
alias Bonfire.UI.Common.OpenModalLive

prop object, :any, required: true
prop object_boundary, :any, default: nil
prop object, :any
prop target, :any, default: nil

def label_id, do: "1ABE1SF0RC0NTENTM0DERAT10N"

def can_label?(context, object, object_boundary \\ nil) do
Bonfire.Boundaries.can?(context, :label, :instance) &&
Types.object_type(object) == Bonfire.Data.Social.Post
# && Types.object_type(object) == Bonfire.Data.Social.Post
Bonfire.Boundaries.can?(context, :moderate, :instance)
end

def labels do
with {:ok, parent_label} <-
Bonfire.Label.Labels.get_or_create(label_id(), "Content Moderation Labels"),
%{edges: []} <- labels_under(parent_label) do
Bonfire.Label.Labels.get_or_create(
"1ABE10VTDATEDGET1ATESTNEWS",
"Get the latest",
parent_label,
"outdated"
)

Bonfire.Label.Labels.get_or_create(
"1ABE1M1S1NF0RMEDGETZEFACTS",
"Stay informed",
parent_label,
"misinformed"
)

Bonfire.Label.Labels.get_or_create(
"1ABE1M1S1EAD1NGBACK2S0VRCE",
"Misleading",
parent_label,
"misleading"
)

labels_under(parent_label)
end
end

def labels_under(parent_label \\ label_id()),
do:
Bonfire.Classify.Categories.list([parent_category: parent_label], skip_boundary_check: true)
end
Loading

0 comments on commit 5cd4c4f

Please sign in to comment.