@@ -17,10 +17,24 @@ defmodule Mobilizon.Activities do
|
||||
very_high: 50
|
||||
)
|
||||
|
||||
@activity_types ["event", "post", "discussion", "resource", "group", "member", "comment"]
|
||||
@activity_types [
|
||||
"event",
|
||||
"post",
|
||||
"conversation",
|
||||
"discussion",
|
||||
"resource",
|
||||
"group",
|
||||
"member",
|
||||
"comment"
|
||||
]
|
||||
@event_activity_subjects ["event_created", "event_updated", "event_deleted", "comment_posted"]
|
||||
@participant_activity_subjects ["event_new_participation"]
|
||||
@post_activity_subjects ["post_created", "post_updated", "post_deleted"]
|
||||
@conversation_activity_subjects [
|
||||
"conversation_created",
|
||||
"conversation_replied",
|
||||
"conversation_event_announcement"
|
||||
]
|
||||
@discussion_activity_subjects [
|
||||
"discussion_created",
|
||||
"discussion_replied",
|
||||
@@ -49,6 +63,7 @@ defmodule Mobilizon.Activities do
|
||||
@settings_activity_subjects ["group_created", "group_updated"]
|
||||
|
||||
@subjects @event_activity_subjects ++
|
||||
@conversation_activity_subjects ++
|
||||
@participant_activity_subjects ++
|
||||
@post_activity_subjects ++
|
||||
@discussion_activity_subjects ++
|
||||
@@ -61,6 +76,7 @@ defmodule Mobilizon.Activities do
|
||||
"actor",
|
||||
"post",
|
||||
"discussion",
|
||||
"conversation",
|
||||
"resource",
|
||||
"member",
|
||||
"group",
|
||||
|
||||
@@ -10,6 +10,7 @@ defmodule Mobilizon.Actors.Actor do
|
||||
alias Mobilizon.{Actors, Addresses, Config, Crypto, Mention, Share}
|
||||
alias Mobilizon.Actors.{ActorOpenness, ActorType, ActorVisibility, Follower, Member}
|
||||
alias Mobilizon.Addresses.Address
|
||||
alias Mobilizon.Conversations.Conversation
|
||||
alias Mobilizon.Discussions.Comment
|
||||
alias Mobilizon.Events.{Event, FeedToken, Participant}
|
||||
alias Mobilizon.Medias.File
|
||||
@@ -196,6 +197,11 @@ defmodule Mobilizon.Actors.Actor do
|
||||
has_many(:owner_shares, Share, foreign_key: :owner_actor_id)
|
||||
many_to_many(:memberships, __MODULE__, join_through: Member)
|
||||
|
||||
many_to_many(:conversations, Conversation,
|
||||
join_through: "conversation_participants",
|
||||
join_keys: [conversation_id: :id, participant_id: :id]
|
||||
)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
|
||||
57
lib/mobilizon/conversations/conversation.ex
Normal file
57
lib/mobilizon/conversations/conversation.ex
Normal file
@@ -0,0 +1,57 @@
|
||||
defmodule Mobilizon.Conversations.Conversation do
|
||||
@moduledoc """
|
||||
Represents a conversation
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
alias Ecto.Changeset
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Conversations.ConversationParticipant
|
||||
alias Mobilizon.Discussions.Comment
|
||||
alias Mobilizon.Events.Event
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
id: String.t(),
|
||||
origin_comment: Comment.t(),
|
||||
last_comment: Comment.t(),
|
||||
participants: list(Actor.t())
|
||||
}
|
||||
|
||||
@required_attrs [:origin_comment_id, :last_comment_id]
|
||||
@optional_attrs [:event_id]
|
||||
@attrs @required_attrs ++ @optional_attrs
|
||||
|
||||
schema "conversations" do
|
||||
belongs_to(:origin_comment, Comment)
|
||||
belongs_to(:last_comment, Comment)
|
||||
belongs_to(:event, Event)
|
||||
has_many(:comments, Comment)
|
||||
|
||||
many_to_many(:participants, Actor,
|
||||
join_through: ConversationParticipant,
|
||||
join_keys: [conversation_id: :id, actor_id: :id],
|
||||
on_replace: :delete
|
||||
)
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(%__MODULE__{} = conversation, attrs) do
|
||||
conversation
|
||||
|> cast(attrs, @attrs)
|
||||
|> maybe_set_participants(attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
end
|
||||
|
||||
defp maybe_set_participants(%Changeset{} = changeset, %{participants: participants})
|
||||
when length(participants) > 0 do
|
||||
put_assoc(changeset, :participants, participants)
|
||||
end
|
||||
|
||||
defp maybe_set_participants(%Changeset{} = changeset, _), do: changeset
|
||||
end
|
||||
40
lib/mobilizon/conversations/conversation_participant.ex
Normal file
40
lib/mobilizon/conversations/conversation_participant.ex
Normal file
@@ -0,0 +1,40 @@
|
||||
defmodule Mobilizon.Conversations.ConversationParticipant do
|
||||
@moduledoc """
|
||||
Represents a conversation participant
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Conversations.Conversation
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
conversation: Conversation.t(),
|
||||
actor: Actor.t(),
|
||||
unread: boolean()
|
||||
}
|
||||
|
||||
@required_attrs [:actor_id, :conversation_id]
|
||||
@optional_attrs [:unread]
|
||||
@attrs @required_attrs ++ @optional_attrs
|
||||
|
||||
schema "conversation_participants" do
|
||||
belongs_to(:conversation, Conversation)
|
||||
belongs_to(:actor, Actor)
|
||||
field(:unread, :boolean, default: true)
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(%__MODULE__{} = conversation, attrs) do
|
||||
conversation
|
||||
|> cast(attrs, @attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
|> foreign_key_constraint(:conversation_id)
|
||||
|> foreign_key_constraint(:actor_id)
|
||||
end
|
||||
end
|
||||
22
lib/mobilizon/conversations/conversation_view.ex
Normal file
22
lib/mobilizon/conversations/conversation_view.ex
Normal file
@@ -0,0 +1,22 @@
|
||||
defmodule Mobilizon.Conversations.ConversationView do
|
||||
@moduledoc """
|
||||
Represents a conversation view for GraphQL API
|
||||
"""
|
||||
|
||||
defstruct [
|
||||
:id,
|
||||
:conversation_participant_id,
|
||||
:origin_comment,
|
||||
:origin_comment_id,
|
||||
:last_comment,
|
||||
:last_comment_id,
|
||||
:event,
|
||||
:event_id,
|
||||
:actor,
|
||||
:actor_id,
|
||||
:unread,
|
||||
:inserted_at,
|
||||
:updated_at,
|
||||
:participants
|
||||
]
|
||||
end
|
||||
344
lib/mobilizon/conversations/conversations.ex
Normal file
344
lib/mobilizon/conversations/conversations.ex
Normal file
@@ -0,0 +1,344 @@
|
||||
defmodule Mobilizon.Conversations do
|
||||
@moduledoc """
|
||||
The conversations context
|
||||
"""
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias Ecto.Changeset
|
||||
alias Ecto.Multi
|
||||
alias Mobilizon.Actors.{Actor, Member}
|
||||
alias Mobilizon.Conversations.{Conversation, ConversationParticipant}
|
||||
alias Mobilizon.Discussions.Comment
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Storage.{Page, Repo}
|
||||
|
||||
@conversation_preloads [
|
||||
:origin_comment,
|
||||
:last_comment,
|
||||
:event,
|
||||
:participants
|
||||
]
|
||||
|
||||
@comment_preloads [
|
||||
:actor,
|
||||
:event,
|
||||
:attributed_to,
|
||||
:in_reply_to_comment,
|
||||
:origin_comment,
|
||||
:replies,
|
||||
:tags,
|
||||
:mentions,
|
||||
:media
|
||||
]
|
||||
|
||||
@doc """
|
||||
Get a conversation by it's ID
|
||||
"""
|
||||
@spec get_conversation(String.t() | integer()) :: Conversation.t() | nil
|
||||
def get_conversation(conversation_id) do
|
||||
Conversation
|
||||
|> Repo.get(conversation_id)
|
||||
|> Repo.preload(@conversation_preloads)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a conversation by it's ID
|
||||
"""
|
||||
@spec get_conversation_participant(String.t() | integer()) :: Conversation.t() | nil
|
||||
def get_conversation_participant(conversation_participant_id) do
|
||||
preload_conversation_participant_details()
|
||||
|> where([cp], cp.id == ^conversation_participant_id)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
def get_participant_by_conversation_and_actor(conversation_id, actor_id) do
|
||||
preload_conversation_participant_details()
|
||||
|> where([cp], cp.conversation_id == ^conversation_id and cp.actor_id == ^actor_id)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
defp preload_conversation_participant_details do
|
||||
ConversationParticipant
|
||||
|> join(:inner, [cp], c in Conversation, on: cp.conversation_id == c.id)
|
||||
|> join(:left, [_cp, c], e in Event, on: c.event_id == e.id)
|
||||
|> join(:inner, [cp], a in Actor, on: cp.actor_id == a.id)
|
||||
|> join(:inner, [_cp, c], lc in Comment, on: c.last_comment_id == lc.id)
|
||||
|> join(:inner, [_cp, c], oc in Comment, on: c.origin_comment_id == oc.id)
|
||||
|> join(:inner, [_cp, c], p in ConversationParticipant, on: c.id == p.conversation_id)
|
||||
|> join(:inner, [_cp, _c, _e, _a, _lc, _oc, p], ap in Actor, on: p.actor_id == ap.id)
|
||||
|> preload([_cp, c, e, a, lc, oc, p, ap],
|
||||
actor: a,
|
||||
conversation:
|
||||
{c, event: e, last_comment: lc, origin_comment: oc, participants: {p, actor: ap}}
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a paginated list of conversations for an actor
|
||||
"""
|
||||
@spec find_conversations_for_actor(Actor.t(), integer | nil, integer | nil) ::
|
||||
Page.t(Conversation.t())
|
||||
def find_conversations_for_actor(%Actor{id: actor_id}, page \\ nil, limit \\ nil) do
|
||||
Conversation
|
||||
|> where([c], c.actor_id == ^actor_id)
|
||||
|> preload(^@conversation_preloads)
|
||||
|> order_by(desc: :updated_at)
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@spec find_conversations_for_event(
|
||||
String.t() | integer,
|
||||
String.t() | integer,
|
||||
integer | nil,
|
||||
integer | nil
|
||||
) :: Page.t(ConversationParticipant.t())
|
||||
def find_conversations_for_event(event_id, actor_id, page \\ nil, limit \\ nil) do
|
||||
ConversationParticipant
|
||||
|> join(:inner, [cp], c in Conversation, on: cp.conversation_id == c.id)
|
||||
|> join(:left, [_cp, c], e in Event, on: c.event_id == e.id)
|
||||
|> join(:inner, [cp], a in Actor, on: cp.actor_id == a.id)
|
||||
|> join(:inner, [_cp, c], lc in Comment, on: c.last_comment_id == lc.id)
|
||||
|> join(:inner, [_cp, c], oc in Comment, on: c.origin_comment_id == oc.id)
|
||||
|> join(:inner, [_cp, c], p in ConversationParticipant, on: c.id == p.conversation_id)
|
||||
|> join(:inner, [_cp, _c, _e, _a, _lc, _oc, p], ap in Actor, on: p.actor_id == ap.id)
|
||||
|> where([_cp, c], c.event_id == ^event_id)
|
||||
|> where([cp], cp.actor_id == ^actor_id)
|
||||
|> preload([_cp, c, e, a, lc, oc, p, ap],
|
||||
actor: a,
|
||||
conversation:
|
||||
{c, event: e, last_comment: lc, origin_comment: oc, participants: {p, actor: ap}}
|
||||
)
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@spec list_conversation_participants_for_actor(
|
||||
integer | String.t(),
|
||||
integer | nil,
|
||||
integer | nil
|
||||
) ::
|
||||
Page.t(ConversationParticipant.t())
|
||||
def list_conversation_participants_for_actor(actor_id, page \\ nil, limit \\ nil) do
|
||||
subquery =
|
||||
ConversationParticipant
|
||||
|> distinct([cp], cp.conversation_id)
|
||||
|> join(:left, [cp], m in Member, on: cp.actor_id == m.parent_id)
|
||||
|> where([cp], cp.actor_id == ^actor_id)
|
||||
|> or_where(
|
||||
[_cp, m],
|
||||
m.actor_id == ^actor_id and m.role in [:creator, :administrator, :moderator]
|
||||
)
|
||||
|
||||
subquery
|
||||
|> subquery()
|
||||
|> order_by([cp], desc: cp.unread, desc: cp.updated_at)
|
||||
|> preload([:actor, conversation: [:last_comment, :participants]])
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@spec list_conversation_participants_for_user(
|
||||
integer | String.t(),
|
||||
integer | nil,
|
||||
integer | nil
|
||||
) ::
|
||||
Page.t(ConversationParticipant.t())
|
||||
def list_conversation_participants_for_user(user_id, page \\ nil, limit \\ nil) do
|
||||
ConversationParticipant
|
||||
|> join(:inner, [cp], a in Actor, on: cp.actor_id == a.id)
|
||||
|> where([_cp, a], a.user_id == ^user_id)
|
||||
|> preload([:actor, conversation: [:last_comment, :participants]])
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@spec list_conversation_participants_for_conversation(integer | String.t()) ::
|
||||
list(ConversationParticipant.t())
|
||||
def list_conversation_participants_for_conversation(conversation_id) do
|
||||
ConversationParticipant
|
||||
|> where([cp], cp.conversation_id == ^conversation_id)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec count_unread_conversation_participants_for_person(integer | String.t()) ::
|
||||
non_neg_integer()
|
||||
def count_unread_conversation_participants_for_person(actor_id) do
|
||||
ConversationParticipant
|
||||
|> where([cp], cp.actor_id == ^actor_id and cp.unread == true)
|
||||
|> Repo.aggregate(:count)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a conversation.
|
||||
"""
|
||||
@spec create_conversation(map()) ::
|
||||
{:ok, Conversation.t()} | {:error, atom(), Changeset.t(), map()}
|
||||
def create_conversation(attrs) do
|
||||
with {:ok, %{comment: %Comment{} = _comment, conversation: %Conversation{} = conversation}} <-
|
||||
Multi.new()
|
||||
|> Multi.insert(
|
||||
:comment,
|
||||
Comment.changeset(
|
||||
%Comment{},
|
||||
Map.merge(attrs, %{
|
||||
actor_id: attrs.actor_id,
|
||||
attributed_to_id: attrs.actor_id,
|
||||
visibility: :private
|
||||
})
|
||||
)
|
||||
)
|
||||
|> Multi.insert(:conversation, fn %{
|
||||
comment: %Comment{
|
||||
id: comment_id,
|
||||
origin_comment_id: origin_comment_id
|
||||
}
|
||||
} ->
|
||||
Conversation.changeset(
|
||||
%Conversation{},
|
||||
Map.merge(attrs, %{
|
||||
last_comment_id: comment_id,
|
||||
origin_comment_id: origin_comment_id || comment_id,
|
||||
participants: attrs.participants
|
||||
})
|
||||
)
|
||||
end)
|
||||
|> Multi.update(:update_comment, fn %{
|
||||
comment: %Comment{} = comment,
|
||||
conversation: %Conversation{id: conversation_id}
|
||||
} ->
|
||||
Comment.changeset(
|
||||
comment,
|
||||
%{conversation_id: conversation_id}
|
||||
)
|
||||
end)
|
||||
|> Multi.update_all(
|
||||
:conversation_participants,
|
||||
fn %{
|
||||
conversation: %Conversation{
|
||||
id: conversation_id
|
||||
}
|
||||
} ->
|
||||
ConversationParticipant
|
||||
|> where(
|
||||
[cp],
|
||||
cp.conversation_id == ^conversation_id and cp.actor_id == ^attrs.actor_id
|
||||
)
|
||||
|> update([cp], set: [unread: false, updated_at: ^NaiveDateTime.utc_now()])
|
||||
end,
|
||||
[]
|
||||
)
|
||||
|> Repo.transaction(),
|
||||
%Conversation{} = conversation <- Repo.preload(conversation, @conversation_preloads) do
|
||||
{:ok, conversation}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create a response to a conversation
|
||||
"""
|
||||
@spec reply_to_conversation(Conversation.t(), map()) ::
|
||||
{:ok, Conversation.t()} | {:error, atom(), Ecto.Changeset.t(), map()}
|
||||
def reply_to_conversation(%Conversation{id: conversation_id} = conversation, attrs \\ %{}) do
|
||||
attrs =
|
||||
Map.merge(attrs, %{
|
||||
conversation_id: conversation_id,
|
||||
actor_id: Map.get(attrs, :creator_id, Map.get(attrs, :actor_id)),
|
||||
origin_comment_id: conversation.origin_comment_id,
|
||||
in_reply_to_comment_id: conversation.last_comment_id,
|
||||
visibility: :private
|
||||
})
|
||||
|
||||
changeset =
|
||||
Comment.changeset(
|
||||
%Comment{},
|
||||
attrs
|
||||
)
|
||||
|
||||
with {:ok, %{comment: %Comment{} = comment, conversation: %Conversation{} = conversation}} <-
|
||||
Multi.new()
|
||||
|> Multi.insert(
|
||||
:comment,
|
||||
changeset
|
||||
)
|
||||
|> Multi.update(:conversation, fn %{comment: %Comment{id: comment_id}} ->
|
||||
Conversation.changeset(
|
||||
conversation,
|
||||
%{last_comment_id: comment_id}
|
||||
)
|
||||
end)
|
||||
|> Multi.update_all(
|
||||
:conversation_participants,
|
||||
fn %{
|
||||
conversation: %Conversation{
|
||||
id: conversation_id
|
||||
}
|
||||
} ->
|
||||
ConversationParticipant
|
||||
|> where(
|
||||
[cp],
|
||||
cp.conversation_id == ^conversation_id and cp.actor_id != ^attrs.actor_id
|
||||
)
|
||||
|> update([cp], set: [unread: true, updated_at: ^NaiveDateTime.utc_now()])
|
||||
end,
|
||||
[]
|
||||
)
|
||||
|> Multi.update_all(
|
||||
:conversation_participants_author,
|
||||
fn %{
|
||||
conversation: %Conversation{
|
||||
id: conversation_id
|
||||
}
|
||||
} ->
|
||||
ConversationParticipant
|
||||
|> where(
|
||||
[cp],
|
||||
cp.conversation_id == ^conversation_id and cp.actor_id == ^attrs.actor_id
|
||||
)
|
||||
|> update([cp], set: [unread: false, updated_at: ^NaiveDateTime.utc_now()])
|
||||
end,
|
||||
[]
|
||||
)
|
||||
|> Repo.transaction(),
|
||||
# Conversation is not updated
|
||||
%Comment{} = comment <- Repo.preload(comment, @comment_preloads) do
|
||||
{:ok, %Conversation{conversation | last_comment: comment}}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Update a conversation.
|
||||
"""
|
||||
@spec update_conversation(Conversation.t(), map()) ::
|
||||
{:ok, Conversation.t()} | {:error, Changeset.t()}
|
||||
def update_conversation(%Conversation{} = conversation, attrs \\ %{}) do
|
||||
conversation
|
||||
|> Conversation.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Delete a conversation.
|
||||
"""
|
||||
@spec delete_conversation(Conversation.t()) ::
|
||||
{:ok, %{comments: {integer() | nil, any()}}} | {:error, :comments, Changeset.t(), map()}
|
||||
def delete_conversation(%Conversation{id: conversation_id}) do
|
||||
Multi.new()
|
||||
|> Multi.delete_all(:comments, fn _ ->
|
||||
where(Comment, [c], c.conversation_id == ^conversation_id)
|
||||
end)
|
||||
# |> Multi.delete(:conversation, conversation)
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Update a conversation participant. Only their read status for now
|
||||
"""
|
||||
@spec update_conversation_participant(ConversationParticipant.t(), map()) ::
|
||||
{:ok, ConversationParticipant.t()} | {:error, Changeset.t()}
|
||||
def update_conversation_participant(
|
||||
%ConversationParticipant{} = conversation_participant,
|
||||
attrs \\ %{}
|
||||
) do
|
||||
conversation_participant
|
||||
|> ConversationParticipant.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
end
|
||||
@@ -9,6 +9,7 @@ defmodule Mobilizon.Discussions.Comment do
|
||||
import Mobilizon.Storage.Ecto, only: [maybe_add_published_at: 1]
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Conversations.Conversation
|
||||
alias Mobilizon.Discussions.{Comment, CommentVisibility, Discussion}
|
||||
alias Mobilizon.Events.{Event, Tag}
|
||||
alias Mobilizon.Medias.Media
|
||||
@@ -49,7 +50,9 @@ defmodule Mobilizon.Discussions.Comment do
|
||||
:local,
|
||||
:is_announcement,
|
||||
:discussion_id,
|
||||
:language
|
||||
:conversation_id,
|
||||
:language,
|
||||
:visibility
|
||||
]
|
||||
@attrs @required_attrs ++ @optional_attrs
|
||||
|
||||
@@ -71,6 +74,7 @@ defmodule Mobilizon.Discussions.Comment do
|
||||
belongs_to(:in_reply_to_comment, Comment, foreign_key: :in_reply_to_comment_id)
|
||||
belongs_to(:origin_comment, Comment, foreign_key: :origin_comment_id)
|
||||
belongs_to(:discussion, Discussion, type: :binary_id)
|
||||
belongs_to(:conversation, Conversation)
|
||||
has_many(:replies, Comment, foreign_key: :origin_comment_id)
|
||||
many_to_many(:tags, Tag, join_through: "comments_tags", on_replace: :delete)
|
||||
has_many(:mentions, Mention)
|
||||
@@ -80,7 +84,7 @@ defmodule Mobilizon.Discussions.Comment do
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the id of the first comment in the discussion.
|
||||
Returns the id of the first comment in the discussion or conversation.
|
||||
"""
|
||||
@spec get_thread_id(t) :: integer
|
||||
def get_thread_id(%__MODULE__{id: id, origin_comment_id: origin_comment_id}) do
|
||||
@@ -181,7 +185,7 @@ defmodule Mobilizon.Discussions.Comment do
|
||||
Tag.changeset(%Tag{}, tag)
|
||||
end
|
||||
|
||||
defp process_mention(tag) do
|
||||
Mention.changeset(%Mention{}, tag)
|
||||
defp process_mention(mention) do
|
||||
Mention.changeset(%Mention{}, mention)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,9 +42,9 @@ defmodule Mobilizon.Discussions do
|
||||
:origin_comment,
|
||||
:replies,
|
||||
:tags,
|
||||
:mentions,
|
||||
:discussion,
|
||||
:media
|
||||
:media,
|
||||
mentions: [:actor]
|
||||
]
|
||||
|
||||
@discussion_preloads [
|
||||
@@ -76,6 +76,7 @@ defmodule Mobilizon.Discussions do
|
||||
Comment
|
||||
|> join(:left, [c], r in Comment, on: r.origin_comment_id == c.id)
|
||||
|> where([c, _], is_nil(c.in_reply_to_comment_id))
|
||||
|> where([c], c.visibility in ^@public_visibility)
|
||||
# TODO: This was added because we don't want to count deleted comments in total_replies.
|
||||
# However, it also excludes all top-level comments with deleted replies from being selected
|
||||
# |> where([_, r], is_nil(r.deleted_at))
|
||||
@@ -197,9 +198,13 @@ defmodule Mobilizon.Discussions do
|
||||
"""
|
||||
@spec update_comment(Comment.t(), map) :: {:ok, Comment.t()} | {:error, Changeset.t()}
|
||||
def update_comment(%Comment{} = comment, attrs) do
|
||||
comment
|
||||
|> Comment.update_changeset(attrs)
|
||||
|> Repo.update()
|
||||
with {:ok, %Comment{} = comment} <-
|
||||
comment
|
||||
|> Comment.update_changeset(attrs)
|
||||
|> Repo.update(),
|
||||
%Comment{} = comment <- Repo.preload(comment, @comment_preloads) do
|
||||
{:ok, comment}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -272,6 +277,19 @@ defmodule Mobilizon.Discussions do
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get all the comments contained into a discussion
|
||||
"""
|
||||
@spec get_comments_in_reply_to_comment_id(integer, integer | nil, integer | nil) ::
|
||||
Page.t(Comment.t())
|
||||
def get_comments_in_reply_to_comment_id(origin_comment_id, page \\ nil, limit \\ nil) do
|
||||
Comment
|
||||
|> where([c], c.id == ^origin_comment_id)
|
||||
|> or_where([c], c.origin_comment_id == ^origin_comment_id)
|
||||
|> order_by(asc: :inserted_at)
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Counts local comments under events
|
||||
"""
|
||||
|
||||
@@ -13,6 +13,7 @@ defmodule Mobilizon.Events.Event do
|
||||
alias Mobilizon.{Addresses, Events, Medias, Mention}
|
||||
alias Mobilizon.Addresses.Address
|
||||
|
||||
alias Mobilizon.Conversations.Conversation
|
||||
alias Mobilizon.Discussions.Comment
|
||||
|
||||
alias Mobilizon.Events.{
|
||||
@@ -126,6 +127,7 @@ defmodule Mobilizon.Events.Event do
|
||||
has_many(:sessions, Session)
|
||||
has_many(:mentions, Mention)
|
||||
has_many(:comments, Comment)
|
||||
has_many(:conversations, Conversation)
|
||||
many_to_many(:contacts, Actor, join_through: "event_contacts", on_replace: :delete)
|
||||
many_to_many(:tags, Tag, join_through: "events_tags", on_replace: :delete)
|
||||
many_to_many(:participants, Actor, join_through: Participant)
|
||||
|
||||
@@ -871,6 +871,21 @@ defmodule Mobilizon.Events do
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the whole list of participants for an event.
|
||||
Default behaviour is to not return :not_approved or :not_confirmed participants
|
||||
"""
|
||||
@spec list_all_participants_for_event(String.t(), list(atom())) :: list(Participant.t())
|
||||
def list_all_participants_for_event(
|
||||
id,
|
||||
roles \\ []
|
||||
) do
|
||||
id
|
||||
|> participants_for_event_query(roles)
|
||||
|> preload([:actor, :event])
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec list_actors_participants_for_event(String.t()) :: [Actor.t()]
|
||||
def list_actors_participants_for_event(id) do
|
||||
id
|
||||
|
||||
@@ -32,8 +32,8 @@ defmodule Mobilizon.Mention do
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(event, attrs) do
|
||||
event
|
||||
def changeset(mention, attrs) do
|
||||
mention
|
||||
|> cast(attrs, @attrs)
|
||||
# TODO: Enforce having either event_id or comment_id
|
||||
|> validate_required(@required_attrs)
|
||||
|
||||
@@ -21,7 +21,14 @@ defmodule Mobilizon.Reports do
|
||||
def get_report(id) do
|
||||
Report
|
||||
|> Repo.get(id)
|
||||
|> Repo.preload([:reported, :reporter, :manager, :events, :comments, :notes])
|
||||
|> Repo.preload([
|
||||
:reported,
|
||||
:reporter,
|
||||
:manager,
|
||||
:events,
|
||||
:notes,
|
||||
comments: [conversation: [:participants]]
|
||||
])
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
Reference in New Issue
Block a user