defmodule Ami.ConversationMessage do use Ecto.Schema import Ecto.{ Query, Changeset } alias Ami.{ User, Conversation, Repo, MessageAttachment } schema "conversation_messages" do field(:body, :string) field(:read, :boolean, default: false) field(:is_group_message, :boolean, default: false) field(:is_archived, :boolean, default: false) field(:is_trashed, :boolean, default: false) field(:attachment_urls, {:array, :string}) field(:created_at, :utc_datetime) field(:updated_at, :utc_datetime) field(:all_user_type, :integer) # NOTE : We will not use this relation anymore. belongs_to(:conversation, Conversation) belongs_to(:sender, User, foreign_key: :sender_id) belongs_to(:receiver, User, foreign_key: :receiver_id) belongs_to(:parent, __MODULE__, foreign_key: :parent_id) has_many(:replies, __MODULE__, foreign_key: :parent_id) has_many(:message_attachments, MessageAttachment, on_delete: :delete_all) end def parent_messages do from(m in __MODULE__, where: is_nil(m.parent_id)) end def parent_messages(query) do from(m in query, where: is_nil(m.parent_id)) end def received_messages(user_id) do from(m in __MODULE__, where: m.receiver_id == ^user_id) end def sent_messages(user_id) do from(m in __MODULE__, where: m.sender_id == ^user_id) end def to_existing_users(query) do query |> Ecto.Query.join(:inner, [c], r in assoc(c, :receiver)) end def from_existing_users(query) do query |> Ecto.Query.join(:inner, [c], r in assoc(c, :sender)) end def unread(query) do query |> Ecto.Query.where(read: false) end def with_limit(limit) do __MODULE__ |> Ecto.Query.limit(^limit) end def with_limit(query, limit) do query |> Ecto.Query.limit(^limit) end def in_descending_order(query) do query |> Ecto.Query.order_by(desc: :created_at) end def preload_sender_profile(query) do query |> Ecto.Query.preload(sender: :profile) end def preload_receiver_profile(query) do query |> Ecto.Query.preload(receiver: :profile) end def preload_subject(query) do query |> Ecto.Query.preload(:conversation) end def preload_replies(query) do reply_preload_query = from( r in __MODULE__, order_by: [asc: r.created_at], preload: [ :message_attachments, [sender: :profile], [receiver: :profile] ] ) query |> Ecto.Query.preload(replies: ^reply_preload_query) end def exclude_ids(query, ids) do from(cm in query, where: cm.id not in ^ids) end def archived_messages(user_id) do __MODULE__ |> Ecto.Query.where(is_archived: true) |> Ecto.Query.where(receiver_id: ^user_id) end def trashed_messages(user_id) do __MODULE__ |> Ecto.Query.where(is_trashed: true) |> Ecto.Query.where(receiver_id: ^user_id) end def count(query) do from(cm in query, select: count(cm.id)) end def messages_for_user(user_id) do from( cm in __MODULE__, where: cm.sender_id == ^user_id, or_where: cm.receiver_id == ^user_id, order_by: [asc: cm.created_at] ) end def for_user_navbar(user_id) do received_messages(user_id) |> unread() |> with_limit(5) |> in_descending_order() |> preload_sender_profile() |> Repo.all() end def for_allusertype_navbar(type, days) do from( c in __MODULE__, where: c.all_user_type == ^type, where: c.created_at >= ^Timex.shift(DateTime.utc_now(), days: -days) ) |> preload_sender_profile() |> Repo.all() end def unread_count_for_user(user_id) do from( cm in __MODULE__, where: cm.receiver_id == ^user_id and cm.read == false, select: count(cm.id) ) |> Repo.one() end def user_type_messages(query, user_id) do user_type = Repo.get(User, user_id).status from( cm in query, or_where: cm.all_user_type == ^user_type ) end def for_all_users(query) do from( cm in query, or_where: cm.all_user_type == 777 ) end def user_received_messages(user_id) do received_messages(user_id) |> from_existing_users() |> Ecto.Query.preload([:message_attachments]) |> in_descending_order() |> preload_sender_profile() |> Repo.all() end def readable_for(user_id) do received_messages(user_id) |> user_type_messages(user_id) |> for_all_users() |> Ecto.Query.where(is_trashed: false) |> Ecto.Query.where(is_archived: false) |> Ecto.Query.preload([:message_attachments]) |> in_descending_order() |> preload_sender_profile() |> preload_replies() |> Repo.all() end def user_sent_messages(user_id) do sent_messages(user_id) |> to_existing_users() |> preload_receiver_profile() |> Ecto.Query.preload([:message_attachments]) |> in_descending_order() |> preload_replies() |> Repo.all() end def user_archived_messages(user_id) do archived_messages(user_id) |> from_existing_users() |> parent_messages() |> preload_sender_profile() |> Ecto.Query.preload([:message_attachments]) |> in_descending_order() |> Repo.all() end def user_trashed_messages(user_id) do trashed_messages(user_id) |> parent_messages() |> preload_sender_profile() |> Ecto.Query.preload([:message_attachments]) |> in_descending_order() |> Repo.all() end def user_archive_count(user_id) do archived_messages(user_id) |> count() |> Repo.one() end def changeset(conversation_message, params \\ %{}) do conversation_message |> cast(params, [ :sender_id, :receiver_id, :body, :attachment_urls, :parent_id, :all_user_type ]) |> cast(%{created_at: DateTime.utc_now(), updated_at: DateTime.utc_now()}, [ :created_at, :updated_at ]) |> validate_required([:sender_id, :receiver_id, :body]) end def create(%{} = params) do %__MODULE__{} |> cast(params, [ :sender_id, :receiver_id, :body, :attachment_urls, :parent_id, :all_user_type ]) |> cast(%{created_at: DateTime.utc_now(), updated_at: DateTime.utc_now()}, [ :created_at, :updated_at ]) |> validate_required([:sender_id, :receiver_id, :body]) |> Repo.insert() end def create_enrollment_report_msg( %{ sender_id: _sender_id, receiver_id: _receiver_id, body: _body, file_path: file_path, enrollment: enrollment, locale: locale } = params ) do filename = case locale do "en" -> "course_report_#{enrollment.id}.pdf" "ar" -> "الدورات_التقرير_#{enrollment.id}.pdf" end file = %Plug.Upload{ path: file_path, content_type: "application/pdf", filename: filename } {:ok, msg} = create(params) MessageAttachment.changeset( %MessageAttachment{ conversation_message_id: msg.id, file_name: filename }, %{file: file} ) |> Repo.insert() Repo.preload(msg, [:message_attachments]) end def create_enrollment_certificate_msg( %{ sender_id: _sender_id, receiver_id: _receiver_id, body: _body, file_path: file_path, enrollment: enrollment, locale: locale } = params ) do filename = case locale do "en" -> "course_certificate_#{enrollment.id}.pdf" "ar" -> "الدورات_الشهادة_#{enrollment.id}.pdf" end file = %Plug.Upload{ path: file_path, content_type: "application/pdf", filename: filename } {:ok, msg} = create(params) MessageAttachment.changeset( %MessageAttachment{ conversation_message_id: msg.id, file_name: filename }, %{file: file} ) |> Repo.insert() Repo.preload(msg, [:message_attachments]) end end