Current section

Files

Jump to
ami lib ami notification.ex
Raw

lib/ami/notification.ex

defmodule Ami.Notification do
use Ecto.Schema
import Ecto.{
Query,
Changeset
}
alias Ami.{
User,
Repo,
Share,
Community,
CoursePeriod,
Enrollment,
Like,
Comment,
Post,
Lesson
}
schema "notifications" do
@timestamps_opts [type: :naive_datetime_usec]
field(:category, :string)
field(:title, :string)
field(:body, :string)
field(:icon, :string)
field(:unread, :boolean, default: true)
field(:broadcasted, :boolean)
field(:created_at, :utc_datetime_usec)
field(:updated_at, :utc_datetime_usec)
belongs_to(:user, User)
end
def unread do
__MODULE__ |> Ecto.Query.where(unread: true)
end
def unread(query) do
query |> Ecto.Query.where(unread: true)
end
def or_unread(query) do
query |> Ecto.Query.or_where(unread: true)
end
def read do
__MODULE__ |> Ecto.Query.where(unread: false)
end
def read(query) do
query |> Ecto.Query.where(unread: false)
end
def for_user(user_id) do
__MODULE__ |> Ecto.Query.where(user_id: ^user_id)
end
def for_user(query, user_id) do
query |> Ecto.Query.where(user_id: ^user_id)
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 order_by_creation_date(query) do
query |> Ecto.Query.order_by(desc: :created_at)
end
def exclude_ids(query, ids) do
from(n in query, where: n.id not in ^ids)
end
def for_user_navbar(user_id, limit \\ 5) do
query = for_user(user_id) |> unread() |> with_limit(limit) |> order_by_creation_date()
Repo.all(query)
end
def unread_count_for_user(user_id) do
from(
n in __MODULE__,
where: n.unread == true and n.user_id == ^user_id,
select: count(n.id)
)
|> Repo.one()
end
def latest_activities_for(user) do
from(
n in __MODULE__,
where: n.user_id == ^user.id,
where: n.category in ["Post", "Comment", "Course", "Community"],
order_by: [desc: :created_at],
limit: 5
)
|> Repo.all()
end
def clear_old_notifications_for_user(user_id, time_in_month \\ 1) do
from(
n in __MODULE__,
where: n.user_id == ^user_id,
where: n.created_at <= ^Timex.shift(Timex.now(), months: -time_in_month)
)
|> Repo.delete_all()
end
def send(notification) do
AmiWeb.Endpoint.broadcast!("notification:#{notification.user_id}", "new_notification", %{
notification_id: notification.id
})
notification
end
def create(%{} = params) do
%__MODULE__{}
|> cast(params, [:user_id, :category, :title, :icon, :body])
|> cast(%{created_at: DateTime.utc_now(), updated_at: DateTime.utc_now()}, [
:created_at,
:updated_at
])
|> validate_required([:user_id, :body])
|> Repo.insert()
end
def notify_of_post_sharing(%{
post_id: post_id,
message: message,
recipient_id: "#all",
user_id: user_id,
community: community,
socket: socket
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
Community.community_members(community)
|> Enum.each(fn recipient ->
post_url = "/my_resources/#{recipient.id}/community/#{community.id}##{post_id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, socket)
notification =
%{
user_id: recipient.id,
category: "Post",
title: "Share",
icon: profile_pic_url,
body: """
#{User.user_name(author)} thinks you would like this Post in #{community.title}. <em>“#{
message
}“</em>. You can see and comment on the post <a href=#{post_url}>here</a>.
.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Post", post_id, user_id)
end)
share_count = share_count_for(post_id, "Post")
{:ok, share_count, post_id}
end
def notify_of_post_sharing(%{
post_id: post_id,
message: message,
recipient_id: recipient_id,
user_id: user_id,
community: community,
socket: socket
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
recipient = Repo.one(from(u in User, where: u.uuid == ^recipient_id))
post_url = "/my_resources/#{recipient.id}/community/#{community.id}##{post_id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, socket)
notification =
%{
user_id: recipient.id,
category: "Post",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Post in #{community.title}. <em>“#{
message
}“</em>. You can see and comment on the post <a href=#{post_url}>here</a>.
.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Post", post_id, user_id)
share_count = share_count_for(post_id, "Post")
{:ok, share_count, post_id}
end
def notify_of_post_sharing(%{
post_id: post_id,
message: message,
recipient_id: "#all",
user_id: user_id,
course_period_id: course_period_id,
lesson: lesson,
socket: socket
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
course_period = Repo.get(CoursePeriod, course_period_id) |> Repo.preload(:course)
recipients = CoursePeriod.students_for(course_period) |> Enum.map(fn enr -> enr.user end)
Enum.map(recipients, fn recipient ->
enrollment =
Repo.one(
from(
e in Enrollment,
where: e.user_id == ^recipient.id and e.course_period_id == ^course_period_id
)
)
post_url =
"/course/#{recipient.id}/#{course_period.course_id}/#{enrollment.id}/show?lesson_id=#{
lesson.id
}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, socket)
notification =
%{
user_id: recipient.id,
category: "Post",
title: "Share",
icon: profile_pic_url,
body: """
#{User.user_name(author)} thinks you would like this Post in #{
course_period.course.title
}, lesson: #{lesson.title}. <em>“#{message}“</em>. You can see and comment on the post <a href=#{
post_url
}>here</a>.
.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Post", post_id, user_id)
end)
share_count = share_count_for(post_id, "Post")
{:ok, share_count, post_id}
end
def notify_of_post_sharing(%{
post_id: post_id,
message: message,
recipient_id: recipient_id,
user_id: user_id,
course_period_id: course_period_id,
lesson: lesson,
socket: socket
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
course_period = Repo.get(CoursePeriod, course_period_id) |> Repo.preload(:course)
recipient = Ami.Repo.one(from(u in Ami.User, where: u.uuid == ^recipient_id))
enrollment =
Repo.one(
from(
e in Enrollment,
where: e.user_id == ^recipient.id and e.course_period_id == ^course_period_id
)
)
post_url =
"/course/#{recipient.id}/#{course_period.course_id}/#{enrollment.id}/show?lesson_id=#{
lesson.id
}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, socket)
notification =
%{
user_id: recipient.id,
category: "Post",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Post in #{
course_period.course.title
}, lesson: #{lesson.title}. <em>“#{message}“</em>. You can see and comment on the post <a href=#{
post_url
}>here</a>.
.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Post", post_id, user_id)
share_count = share_count_for(post_id, "Post")
{:ok, share_count, post_id}
end
def notify_of_liking(%Like{likeable_type: "Post"} = like, %{
recipient_id: recipient_id,
context: %Community{} = community,
socket: socket
}) do
post_url = "/my_resources/#{recipient_id}/community/#{community.id}##{like.likeable_id}"
profile_pic_url = AmiWeb.LayoutView.user_image(like.user.profile, socket)
%{
user_id: recipient_id,
category: "Post",
title: "Like",
icon: profile_pic_url,
body:
"#{User.user_name(like.user)} liked your <a href=#{post_url}>post</a> in #{
community.title
}"
}
|> create_and_send()
end
def notify_of_liking(%Like{likeable_type: "Post"} = like, %{
recipient_id: recipient_id,
context: %Lesson{} = lesson,
socket: socket
}) do
post = Repo.get(Post, like.likeable_id) |> Repo.preload(course_period: :course)
enrollment =
Repo.one(
from(
e in Enrollment,
where: e.user_id == ^recipient_id and e.course_period_id == ^post.course_period_id
)
)
post_url =
"/course/#{recipient_id}/#{post.course_period.course_id}/#{enrollment.id}/show?lesson_id=#{
lesson.id
}"
profile_pic_url = AmiWeb.LayoutView.user_image(like.user.profile, socket)
%{
user_id: recipient_id,
category: "Post",
title: "Like",
icon: profile_pic_url,
body:
"#{User.user_name(like.user)} liked your <a href=#{post_url}>post</a> in #{
post.course_period.course.title
} course - lesson: #{lesson.title}"
}
|> create_and_send()
end
def notify_of_liking(%Like{likeable_type: "Comment"} = like, %{
recipient_id: recipient_id,
context: %Community{} = community,
socket: socket
}) do
profile_pic_url = AmiWeb.LayoutView.user_image(like.user.profile, socket)
%{
user_id: recipient_id,
category: "Comment",
title: "Like",
icon: profile_pic_url,
body:
"#{User.user_name(like.user)} liked your comment in #{community.title} community wall."
}
|> create_and_send()
end
def notify_of_liking(%Like{likeable_type: "Comment"} = like, %{
recipient_id: recipient_id,
context: %Lesson{} = lesson,
socket: socket
}) do
profile_pic_url = AmiWeb.LayoutView.user_image(like.user.profile, socket)
%{
user_id: recipient_id,
category: "Comment",
title: "Like",
icon: profile_pic_url,
body: "#{User.user_name(like.user)} liked your comment in #{lesson.title} lesson."
}
|> create_and_send()
end
def notify_of_commenting(%Comment{commentable_type: "Post"} = comment, %{
recipient_id: recipient_id,
context: %Community{} = community,
socket: socket
}) do
profile_pic_url = AmiWeb.LayoutView.user_image(comment.user.profile, socket)
post_url = "/my_resources/#{recipient_id}/community/#{community.id}##{comment.commentable_id}"
%{
user_id: recipient_id,
category: "Post",
title: "Comment",
icon: profile_pic_url,
body:
"#{User.user_name(comment.user)} has commented on your post in #{community.title} community wall - <a href=#{
post_url
}>reply now!</a>"
}
|> create_and_send()
end
def notify_of_commenting(%Comment{commentable_type: "Post"} = comment, %{
recipient_id: recipient_id,
context: %Lesson{} = lesson,
socket: socket
}) do
profile_pic_url = AmiWeb.LayoutView.user_image(comment.user.profile, socket)
post = Repo.get(Post, comment.commentable_id) |> Repo.preload(course_period: :course)
%{
user_id: recipient_id,
category: "Post",
title: "Comment",
icon: profile_pic_url,
body:
"#{User.user_name(comment.user)} has commented on your post in #{
post.course_period.course.title
} course - lesson: #{lesson.title}"
}
|> create_and_send()
end
def notify_of_tool_sharing(%{
tool_id: tool_id,
message: message,
recipient_id: "#all",
user_id: user_id,
community: community,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
Community.community_members(community)
|> Enum.each(fn recipient ->
tool_url = "/my_resources/#{recipient.id}/tool/#{tool_id}?community_id=#{community.id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Tool",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Tool in #{community.title}. <em>“#{
message
}“</em>. You can see the tool <a href=#{tool_url}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Tool", tool_id, user_id)
end)
share_count = share_count_for(tool_id, "Tool")
{:ok, share_count, tool_id}
end
def notify_of_tool_sharing(%{
tool_id: tool_id,
message: message,
recipient_id: recipient_id,
user_id: user_id,
community: %Community{} = community,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
recipient = Repo.one(from(u in User, where: u.uuid == ^recipient_id))
tool_url = "/my_resources/#{recipient.id}/tool/#{tool_id}?community_id=#{community.id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Tool",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Tool in #{community.title}. <em>“#{
message
}“</em>. You can see the tool <a href=#{tool_url}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Tool", tool_id, user_id)
share_count = share_count_for(tool_id, "Tool")
{:ok, share_count, tool_id}
end
def notify_of_tool_sharing(%{
tool_id: tool_id,
message: message,
user_id: user_id,
recipient_id: recipient_id,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
recipient = Repo.one(from(u in User, where: u.uuid == ^recipient_id))
tool_url = "/my_resources/#{recipient.id}/tool/#{tool_id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Tool",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Tool. <em>“#{message}“</em>. You can see the tool <a href=#{
tool_url
}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("Tool", tool_id, user_id)
share_count = share_count_for(tool_id, "Tool")
{:ok, share_count, tool_id}
end
def notify_of_toolkit_sharing(%{
toolkit_id: toolkit_id,
message: message,
recipient_id: "#all",
user_id: user_id,
community: community,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
Community.community_members(community)
|> Enum.each(fn recipient ->
toolkit_url =
"/my_resources/#{recipient.id}/toolkit/#{toolkit_id}?community_id=#{community.id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Toolkit",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Toolkit in #{community.title}. <em>“#{
message
}“</em>. You can check it <a href=#{toolkit_url}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("ToolKit", toolkit_id, user_id)
end)
share_count = share_count_for(toolkit_id, "ToolKit")
{:ok, share_count, toolkit_id}
end
def notify_of_toolkit_sharing(%{
toolkit_id: toolkit_id,
message: message,
recipient_id: recipient_id,
user_id: user_id,
community: community,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
recipient = Repo.one(from(u in User, where: u.uuid == ^recipient_id))
toolkit_url =
"/my_resources/#{recipient.id}/toolkit/#{toolkit_id}?community_id=#{community.id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Toolkit",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Toolkit in #{community.title}. <em>“#{
message
}“</em>. You can check it <a href=#{toolkit_url}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("ToolKit", toolkit_id, user_id)
share_count = share_count_for(toolkit_id, "ToolKit")
{:ok, share_count, toolkit_id}
end
def notify_of_toolkit_sharing(%{
toolkit_id: toolkit_id,
message: message,
recipient_id: recipient_id,
user_id: user_id,
conn: conn
}) do
author = Repo.get(User, user_id) |> Repo.preload(:profile)
recipient = Repo.one(from(u in User, where: u.uuid == ^recipient_id))
toolkit_url = "/my_resources/#{recipient.id}/toolkit/#{toolkit_id}"
profile_pic_url = AmiWeb.LayoutView.user_image(author.profile, conn)
notification =
%{
user_id: recipient.id,
category: "Toolkit",
title: "Share",
icon: profile_pic_url,
body: """
#{Ami.User.user_name(author)} thinks you would like this Toolkit. <em>“#{message}“</em>. You can check it <a href=#{
toolkit_url
}>here</a>.
"""
}
|> create_and_send()
if %__MODULE__{} = notification, do: create_share("ToolKit", toolkit_id, user_id)
share_count = share_count_for(toolkit_id, "ToolKit")
{:ok, share_count, toolkit_id}
end
def create_and_send(notification_params) do
case __MODULE__.create(notification_params) do
{:ok, notification} ->
__MODULE__.send(notification)
{:error, changeset} ->
{:error, changeset}
end
end
def create_and_send?(notification_params) do
beginning_of_day = Timex.beginning_of_day(DateTime.utc_now())
end_of_day = Timex.end_of_day(DateTime.utc_now())
count =
Ami.Repo.one(
from(
n in __MODULE__,
where: n.user_id == ^notification_params[:user_id],
where: n.category == ^notification_params[:category],
where: n.title == ^notification_params[:title],
where: n.body == ^notification_params[:body],
where: n.created_at >= ^beginning_of_day and n.created_at <= ^end_of_day,
select: count(n.id)
)
)
if count == 0, do: create_and_send(notification_params)
end
defp share_count_for(id, type) do
Repo.one(
from(
s in Ami.Share,
where: s.shareable_type == ^type and s.shareable_id == ^id,
select: count(s.id)
)
)
end
defp create_share(type, resource_id, user_id) do
Share.create_share(%{
shareable_type: type,
shareable_id: resource_id,
user_id: user_id,
created_at: DateTime.utc_now(),
updated_at: DateTime.utc_now()
})
end
end