Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/groupher_server/cms/article_comment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ defmodule GroupherServer.CMS.ArticleComment do

@type t :: %ArticleComment{}
schema "articles_comments" do
belongs_to(:author, Accounts.User, foreign_key: :author_id)

field(:body_html, :string)
# 是否被折叠
field(:is_folded, :boolean, default: false)
Expand All @@ -71,7 +73,6 @@ defmodule GroupherServer.CMS.ArticleComment do
field(:is_pinned, :boolean, default: false)
field(:viewer_has_upvoted, :boolean, default: false, virtual: true)

belongs_to(:author, Accounts.User, foreign_key: :author_id)
belongs_to(:post, Post, foreign_key: :post_id)
belongs_to(:job, Job, foreign_key: :job_id)
belongs_to(:reply_to, ArticleComment, foreign_key: :reply_to_id)
Expand Down
9 changes: 9 additions & 0 deletions lib/groupher_server/cms/article_comment_user_emotion.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,13 @@ defmodule GroupherServer.CMS.ArticleCommentUserEmotion do
|> foreign_key_constraint(:user_id)
|> foreign_key_constraint(:recived_user_id)
end

def update_changeset(%ArticleCommentUserEmotion{} = struct, attrs) do
struct
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> foreign_key_constraint(:article_comment_id)
|> foreign_key_constraint(:user_id)
|> foreign_key_constraint(:recived_user_id)
end
end
9 changes: 6 additions & 3 deletions lib/groupher_server/cms/cms.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ defmodule GroupherServer.CMS do
ArticleOperation,
ArticleReaction,
ArticleComment,
ArticleCommentEmotion,
CommentCURD,
CommunitySync,
CommentReaction,
CommunityCURD,
CommunityOperation,
PassportCURD,
Expand Down Expand Up @@ -126,15 +126,18 @@ defmodule GroupherServer.CMS do
defdelegate list_article_comments_participators(thread, content_id, filters), to: ArticleComment

defdelegate create_article_comment(thread, article_id, args, user), to: ArticleComment
defdelegate update_article_comment(comment, content), to: ArticleComment
defdelegate delete_article_comment(comment), to: ArticleComment

defdelegate upvote_article_comment(comment_id, user), to: ArticleComment
defdelegate undo_upvote_article_comment(comment_id, user), to: ArticleComment
defdelegate delete_article_comment(comment_id, user), to: ArticleComment
defdelegate reply_article_comment(comment_id, args, user), to: ArticleComment

defdelegate pin_article_comment(comment_id), to: ArticleComment
defdelegate undo_pin_article_comment(comment_id), to: ArticleComment

defdelegate emotion_to_comment(comment_id, args, user), to: ArticleComment
defdelegate emotion_to_comment(comment_id, args, user), to: ArticleCommentEmotion
defdelegate undo_emotion_to_comment(comment_id, args, user), to: ArticleCommentEmotion
defdelegate fold_article_comment(comment_id, user), to: ArticleComment
defdelegate unfold_article_comment(comment_id, user), to: ArticleComment
defdelegate report_article_comment(comment_id, user), to: ArticleComment
Expand Down
106 changes: 24 additions & 82 deletions lib/groupher_server/cms/delegates/article_comment.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
ArticlePinedComment,
ArticleCommentUpvote,
ArticleCommentReply,
ArticleCommentUserEmotion,
Embeds,
Post,
Job
}

alias Ecto.Multi

@max_latest_emotion_users_count ArticleComment.max_latest_emotion_users_count()
@max_participator_count ArticleComment.max_participator_count()
@max_parent_replies_count ArticleComment.max_parent_replies_count()
@default_emotions Embeds.ArticleCommentEmotion.default_emotions()
Expand Down Expand Up @@ -157,24 +155,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
end
end

@doc "delete article comment"
def delete_article_comment(comment_id, %User{} = _user) do
with {:ok, comment} <- ORM.find(ArticleComment, comment_id) do
Multi.new()
|> Multi.run(:update_article_comments_count, fn _, _ ->
update_article_comments_count(comment, :dec)
end)
|> Multi.run(:remove_pined_comment, fn _, _ ->
ORM.findby_delete(ArticlePinedComment, %{article_comment_id: comment.id})
end)
|> Multi.run(:delete_article_comment, fn _, _ ->
ORM.update(comment, %{body_html: @delete_hint, is_deleted: true})
end)
|> Repo.transaction()
|> upsert_comment_result()
end
end

def fold_article_comment(%ArticleComment{} = comment, %User{} = _user) do
comment |> ORM.update(%{is_folded: true})
end
Expand Down Expand Up @@ -224,68 +204,8 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
end
end

@doc "make emotion to a comment"
def emotion_to_comment(comment_id, emotion, %User{} = user) do
with {:ok, comment} <-
ORM.find(ArticleComment, comment_id) do
Multi.new()
|> Multi.run(:create_user_emotion, fn _, _ ->
args =
Map.put(
%{
article_comment_id: comment.id,
recived_user_id: comment.author_id,
user_id: user.id
},
:"#{emotion}",
true
)

{:ok, _} = ArticleCommentUserEmotion |> ORM.create(args)
end)
|> Multi.run(:query_emotion_status, fn _, _ ->
# 每次被 emotion 动作触发后重新查询,主要原因
# 1.并发下保证数据准确,类似 views 阅读数的统计
# 2. 前端使用 nickname 而非 login 展示,如果用户改了 nickname, 可以"自动纠正"
query =
from(a in ArticleCommentUserEmotion,
join: user in User,
on: a.user_id == user.id,
where: a.article_comment_id == ^comment.id,
where: field(a, ^emotion) == true,
select: %{login: user.login, nickname: user.nickname}
)

emotioned_user_info_list = Repo.all(query) |> Enum.uniq()
emotioned_user_count = length(emotioned_user_info_list)

{:ok, %{user_list: emotioned_user_info_list, user_count: emotioned_user_count}}
end)
|> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} ->
updated_emotions =
%{}
|> Map.put(:"#{emotion}_count", status.user_count)
|> Map.put(
:"#{emotion}_user_logins",
status.user_list |> Enum.map(& &1.login)
)
|> Map.put(
:"latest_#{emotion}_users",
Enum.slice(status.user_list, 0, @max_latest_emotion_users_count)
)

comment
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_embed(:emotions, updated_emotions)
|> Repo.update()
end)
|> Repo.transaction()
|> upsert_comment_result
end
end

@doc """
Creates a comment for psot, job ...
creates a comment for article like psot, job ...
"""
def create_article_comment(thread, article_id, content, %User{} = user) do
with {:ok, info} <- match(thread),
Expand All @@ -307,6 +227,29 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
end
end

@doc """
update a comment for article like psot, job ...
"""
def update_article_comment(%ArticleComment{} = article_comment, content) do
article_comment |> ORM.update(%{body_html: content})
end

@doc "delete article comment"
def delete_article_comment(%ArticleComment{} = comment) do
Multi.new()
|> Multi.run(:update_article_comments_count, fn _, _ ->
update_article_comments_count(comment, :dec)
end)
|> Multi.run(:remove_pined_comment, fn _, _ ->
ORM.findby_delete(ArticlePinedComment, %{article_comment_id: comment.id})
end)
|> Multi.run(:delete_article_comment, fn _, _ ->
ORM.update(comment, %{body_html: @delete_hint, is_deleted: true})
end)
|> Repo.transaction()
|> upsert_comment_result()
end

@doc "reply to exsiting comment"
def reply_article_comment(comment_id, content, %User{} = user) do
with {:ok, target_comment} <-
Expand Down Expand Up @@ -704,7 +647,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
defp upsert_comment_result({:ok, %{add_reply_to: result}}), do: {:ok, result}
defp upsert_comment_result({:ok, %{check_article_author_upvoted: result}}), do: {:ok, result}
defp upsert_comment_result({:ok, %{update_report_flag: result}}), do: {:ok, result}
defp upsert_comment_result({:ok, %{update_comment_emotion: result}}), do: {:ok, result}
defp upsert_comment_result({:ok, %{update_comment_flag: result}}), do: {:ok, result}
defp upsert_comment_result({:ok, %{delete_article_comment: result}}), do: {:ok, result}

Expand Down
131 changes: 131 additions & 0 deletions lib/groupher_server/cms/delegates/article_comment_emotion.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
defmodule GroupherServer.CMS.Delegate.ArticleCommentEmotion do
@moduledoc """
CURD and operations for article comments
"""
import Ecto.Query, warn: false

alias Helper.ORM
alias GroupherServer.{Accounts, CMS, Repo}

alias Accounts.User
alias CMS.{ArticleComment, ArticleCommentUserEmotion}

alias Ecto.Multi

@type t_user_list :: [%{login: String.t()}]
@type t_mention_status :: %{user_list: t_user_list, user_count: Integer.t()}

@max_latest_emotion_users_count ArticleComment.max_latest_emotion_users_count()

@doc "make emotion to a comment"
def emotion_to_comment(comment_id, emotion, %User{} = user) do
with {:ok, comment} <- ORM.find(ArticleComment, comment_id, preload: :author) do
Multi.new()
|> Multi.run(:create_user_emotion, fn _, _ ->
target = %{
article_comment_id: comment.id,
recived_user_id: comment.author.id,
user_id: user.id
}

args = Map.put(target, :"#{emotion}", true)

case ORM.find_by(ArticleCommentUserEmotion, target) do
{:ok, article_comment_user_emotion} -> article_comment_user_emotion |> ORM.update(args)
{:error, _} -> ArticleCommentUserEmotion |> ORM.create(args)
end
end)
|> Multi.run(:query_emotion_status, fn _, _ ->
query_emotion_status(comment, emotion)
end)
|> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} ->
update_comment_emotion(comment, emotion, status, user)
end)
|> Repo.transaction()
|> update_emotion_result
end
end

def undo_emotion_to_comment(comment_id, emotion, %User{} = user) do
with {:ok, comment} <- ORM.find(ArticleComment, comment_id, preload: :author) do
Multi.new()
|> Multi.run(:update_user_emotion, fn _, _ ->
target = %{
article_comment_id: comment.id,
recived_user_id: comment.author.id,
user_id: user.id
}

{:ok, article_comment_user_emotion} = ORM.find_by(ArticleCommentUserEmotion, target)
args = Map.put(target, :"#{emotion}", false)
article_comment_user_emotion |> ORM.update(args)
end)
|> Multi.run(:query_emotion_status, fn _, _ ->
query_emotion_status(comment, emotion)
end)
|> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} ->
update_comment_emotion(comment, emotion, status, user)
end)
|> Repo.transaction()
|> update_emotion_result
end
end

@spec query_emotion_status(ArticleComment.t(), Atom.t()) :: {:ok, t_mention_status}
defp query_emotion_status(comment, emotion) do
# 每次被 emotion 动作触发后重新查询,主要原因
# 1.并发下保证数据准确,类似 views 阅读数的统计
# 2. 前端使用 nickname 而非 login 展示,如果用户改了 nickname, 可以"自动纠正"
query =
from(a in ArticleCommentUserEmotion,
join: user in User,
on: a.user_id == user.id,
where: a.article_comment_id == ^comment.id,
where: field(a, ^emotion) == true,
select: %{login: user.login, nickname: user.nickname}
)

emotioned_user_info_list = Repo.all(query) |> Enum.uniq()
emotioned_user_count = length(emotioned_user_info_list)

{:ok, %{user_list: emotioned_user_info_list, user_count: emotioned_user_count}}
end

@spec update_comment_emotion(ArticleComment.t(), Atom.t(), t_mention_status, User.t()) ::
{:ok, ArticleComment.t()} | {:error, any}
defp update_comment_emotion(comment, emotion, status, user) do
%{user_count: user_count, user_list: user_list} = status

emotions =
%{}
|> Map.put(:"#{emotion}_count", user_count)
|> Map.put(:"#{emotion}_user_logins", user_list |> Enum.map(& &1.login))
|> Map.put(
:"latest_#{emotion}_users",
Enum.slice(user_list, 0, @max_latest_emotion_users_count)
)

viewer_has_emotioned = user.login in Map.get(emotions, :"#{emotion}_user_logins")
emotions = emotions |> Map.put(:"viewer_has_#{emotion}ed", viewer_has_emotioned)

comment
|> Ecto.Changeset.change()
|> Ecto.Changeset.put_embed(:emotions, emotions)
|> Repo.update()
# virtual field can not be updated
|> add_viewer_emotioned_ifneed(emotions)
end

defp add_viewer_emotioned_ifneed({:error, error}, _), do: {:error, error}

defp add_viewer_emotioned_ifneed({:ok, comment}, emotions) do
# Map.merge(comment, %{emotion: emotions})
{:ok, Map.merge(comment, %{emotion: emotions})}
end

defp update_emotion_result({:ok, %{update_comment_emotion: result}}), do: {:ok, result}

defp update_emotion_result({:error, _, result, _steps}) do
{:error, result}
end
end
21 changes: 19 additions & 2 deletions lib/groupher_server_web/middleware/passport_loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do
import Helper.ErrorCode
import ShortMaps

alias GroupherServer.CMS
alias Helper.ORM
alias GroupherServer.CMS

alias CMS.{ArticleComment}

def call(%{errors: errors} = resolution, _) when length(errors) > 0, do: resolution

Expand All @@ -24,8 +26,20 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do
%{resolution | arguments: arguments}

{:error, err_msg} ->
resolution |> handle_absinthe_error(err_msg, ecode(:passport))
end
end

@doc "load article comment"
def call(%{context: %{cur_user: _}, arguments: ~m(id)a} = resolution, source: :article_comment) do
case ORM.find(ArticleComment, id, preload: :author) do
{:ok, article_comment} ->
resolution
|> handle_absinthe_error(err_msg, ecode(:passport))
|> load_owner_info(:article_comment, article_comment)
|> load_source(article_comment)

{:error, err_msg} ->
resolution |> handle_absinthe_error(err_msg, ecode(:passport))
end
end

Expand Down Expand Up @@ -83,6 +97,9 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do
def load_owner_info(%{context: %{cur_user: cur_user}} = resolution, react, content) do
content_author_id =
cond do
react == :article_comment ->
content.author.id

react == :comment ->
content.author.id

Expand Down
Loading