Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

refactor(user): move users query to own fields#371

Merged
mydearxym merged 14 commits intodevfromusers_count_fields
May 29, 2021
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
14 commits
Select commitHold shift + click to select a range
5e9d692
refactor(user): contribute field
mydearxymMay 28, 2021
ba1fd61
refactor(user): default contributes
mydearxymMay 28, 2021
8f6df86
refactor(user): default contributes
mydearxymMay 28, 2021
e3df213
fix(user): contrutess model setting
mydearxymMay 28, 2021
21642a2
refactor(user): wip
mydearxymMay 28, 2021
0b19ed3
refactor(user): basic follower status
mydearxymMay 28, 2021
2953902
refactor(user): wip
mydearxymMay 28, 2021
bb6055d
refactor(user): follow states for paged api
mydearxymMay 29, 2021
916fd52
refactor(user): follow count move to table
mydearxymMay 29, 2021
d2c84a3
refactor(user): follow queries use login
mydearxymMay 29, 2021
de7f384
fix(user): login args in test
mydearxymMay 29, 2021
c5433e7
fix(user): login args in test
mydearxymMay 29, 2021
9f61d1f
fix(user): login args in test
mydearxymMay 29, 2021
47d575a
fix(user): login args in test
mydearxymMay 29, 2021
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
2 changes: 1 addition & 1 deletioncover/excoveralls.json
View file
Open in desktop

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletionslib/groupher_server/accounts/accounts.ex
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,11 @@ defmodule GroupherServer.Accounts do
}

# profile
defdelegate read_user(user), to: Profile
defdelegate read_user(login, user), to: Profile
defdelegate paged_users(filter), to: Profile
defdelegate paged_users(filter, user), to: Profile

defdelegate update_profile(user, attrs), to: Profile
defdelegate update_geo(user, remote_ip), to: Profile
defdelegate github_signin(github_user), to: Profile
Expand DownExpand Up@@ -46,8 +51,10 @@ defmodule GroupherServer.Accounts do
# fans
defdelegate follow(user, follower), to: Fans
defdelegate undo_follow(user, follower), to: Fans
defdelegate fetch_followers(user, filter), to: Fans
defdelegate fetch_followings(user, filter), to: Fans
defdelegate paged_followers(user, filter), to: Fans
defdelegate paged_followers(user, filter, cur_user), to: Fans
defdelegate paged_followings(user, filter), to: Fans
defdelegate paged_followings(user, filter, cur_user), to: Fans

# upvoted articles
defdelegate paged_upvoted_articles(user_id, filter), to: UpvotedArticles
Expand Down
195 changes: 136 additions & 59 deletionslib/groupher_server/accounts/delegates/fans.ex
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,118 +3,127 @@ defmodule GroupherServer.Accounts.Delegate.Fans do
user followers / following related
"""
import Ecto.Query, warn: false
import Helper.Utils, only: [done: 1]
import Helper.Utils, only: [done: 1, ensure: 2]
import Helper.ErrorCode
import ShortMaps

alias Helper.{ORM, QueryBuilder, SpecType}
alias GroupherServer.{Accounts, Repo}

alias GroupherServer.Accounts.{User, UserFollower, UserFollowing}
alias GroupherServer.Accounts.{User,Embeds,UserFollower, UserFollowing}

alias Ecto.Multi

@default_user_meta Embeds.UserMeta.default_meta()

@doc """
follow a user
"""
@spec follow(User.t(), User.t()) :: {:ok, User.t()} | SpecType.gq_error()
def follow(%User{id: user_id}, %User{id: follower_id}) do
with true <- to_string(user_id) !== to_string(follower_id),
{:ok,_follow_user} <- ORM.find(User, follower_id) do
{:ok,target_user} <- ORM.find(User, follower_id) do
Multi.new()
|> Multi.insert(
:create_follower,
# UserFollower.changeset(%UserFollower{}, ~m(user_id follower_id)a)
UserFollower.changeset(%UserFollower{}, %{user_id: follower_id, follower_id: user_id})
UserFollower.changeset(%UserFollower{}, %{user_id: target_user.id, follower_id: user_id})
)
|> Multi.insert(
:create_following,
UserFollowing.changeset(%UserFollowing{}, %{user_id: user_id, following_id: follower_id})
UserFollowing.changeset(%UserFollowing{}, %{
user_id: user_id,
following_id: target_user.id
})
)
|> Multi.run(:update_user_follow_info, fn _, _ ->
update_user_follow_info(target_user, user_id, :add)
end)
|> Multi.run(:add_achievement, fn _, _ ->
Accounts.achieve(%User{id:follower_id}, :inc, :follow)
Accounts.achieve(%User{id:target_user.id}, :inc, :follow)
end)
|> Repo.transaction()
|>follow_result()
|>result()
else
false ->
{:error, [message: "can't follow yourself", code: ecode(:self_conflict)]}

{:error, reason} ->
{:error, [message: reason, code: ecode(:not_exsit)]}
false -> {:error, [message: "can't follow yourself", code: ecode(:self_conflict)]}
{:error, reason} -> {:error, [message: reason, code: ecode(:not_exsit)]}
end
end

@spec follow_result({:ok, map()}) :: SpecType.done()
defp follow_result({:ok, %{create_follower: user_follower}}) do
User |> ORM.find(user_follower.user_id)
end

defp follow_result({:error, :create_follower, %Ecto.Changeset{}, _steps}) do
{:error, [message: "already followed", code: ecode(:already_did)]}
end

defp follow_result({:error, :create_follower, _result, _steps}) do
{:error, [message: "already followed", code: ecode(:already_did)]}
end

defp follow_result({:error, :create_following, _result, _steps}) do
{:error, [message: "follow fails", code: ecode(:react_fails)]}
end

defp follow_result({:error, :add_achievement, _result, _steps}) do
{:error, [message: "follow acieve fails", code: ecode(:react_fails)]}
end

@doc """
undo a follow action to a user
"""
@spec undo_follow(User.t(), User.t()) :: {:ok, User.t()} | SpecType.gq_error()
def undo_follow(%User{id: user_id}, %User{id: follower_id}) do
with true <- to_string(user_id) !== to_string(follower_id),
{:ok,_follow_user} <- ORM.find(User, follower_id) do
{:ok,target_user} <- ORM.find(User, follower_id) do
Multi.new()
|> Multi.run(:delete_follower, fn _, _ ->
ORM.findby_delete!(UserFollower, %{user_id:follower_id, follower_id: user_id})
ORM.findby_delete!(UserFollower, %{user_id:target_user.id, follower_id: user_id})
end)
|> Multi.run(:delete_following, fn _, _ ->
ORM.findby_delete!(UserFollowing, %{user_id: user_id, following_id: follower_id})
ORM.findby_delete!(UserFollowing, %{user_id: user_id, following_id: target_user.id})
end)
|> Multi.run(:update_user_follow_info, fn _, _ ->
update_user_follow_info(target_user, user_id, :remove)
end)
|> Multi.run(:minus_achievement, fn _, _ ->
Accounts.achieve(%User{id:follower_id}, :dec, :follow)
Accounts.achieve(%User{id:target_user.id}, :dec, :follow)
end)
|> Repo.transaction()
|>undo_follow_result()
|>result()
else
false ->
{:error, [message: "can't undo follow yourself", code: ecode(:self_conflict)]}

{:error, reason} ->
{:error, [message: reason, code: ecode(:not_exsit)]}
false -> {:error, [message: "can't undo follow yourself", code: ecode(:self_conflict)]}
{:error, reason} -> {:error, [message: reason, code: ecode(:not_exsit)]}
end
end

defp undo_follow_result({:ok, %{delete_follower: user_follower}}) do
User |> ORM.find(user_follower.user_id)
end
# update follow in user meta
defp update_user_follow_info(%User{} = target_user, user_id, opt) do
with {:ok, user} <- ORM.find(User, user_id) do
target_user_meta = ensure(target_user.meta, @default_user_meta)
user_meta = ensure(user.meta, @default_user_meta)

defp undo_follow_result({:error, :delete_follower, _result, _steps}) do
{:error, [message: "already unfollowed", code: ecode(:already_did)]}
end
follower_user_ids =
case opt do
:add -> (target_user_meta.follower_user_ids ++ [user_id]) |> Enum.uniq()
:remove -> (target_user_meta.follower_user_ids -- [user_id]) |> Enum.uniq()
end

defp undo_follow_result({:error, :delete_following, _result, _steps}) do
{:error, [message: "unfollow fails", code: ecode(:react_fails)]}
end
following_user_ids =
case opt do
:add -> (user_meta.following_user_ids ++ [target_user.id]) |> Enum.uniq()
:remove -> (user_meta.following_user_ids -- [target_user.id]) |> Enum.uniq()
end

defp undo_follow_result({:error, :minus_achievement, _result, _steps}) do
{:error, [message: "follow acieve fails", code: ecode(:react_fails)]}
Multi.new()
|> Multi.run(:update_follower_meta, fn _, _ ->
followers_count = length(follower_user_ids)
meta = Map.merge(target_user_meta, %{follower_user_ids: follower_user_ids})

ORM.update_meta(target_user, meta, changes: %{followers_count: followers_count})
end)
|> Multi.run(:update_following_meta, fn _, _ ->
followings_count = length(following_user_ids)
meta = Map.merge(user_meta, %{following_user_ids: following_user_ids})

ORM.update_meta(user, meta, changes: %{followings_count: followings_count})
end)
|> Repo.transaction()
|> result()
end
end

@doc """
get paged followers of a user
"""
@spec fetch_followers(User.t(), map()) :: {:ok, map()} | {:error, String.t()}
def fetch_followers(%User{id: user_id}, filter) do
def paged_followers(%User{id: user_id}, filter, %User{} = cur_user) do
paged_followers(%User{id: user_id}, filter)
|> mark_viewer_follow_status(cur_user)
|> done
end

@spec paged_followers(User.t(), map()) :: {:ok, map()} | {:error, String.t()}
def paged_followers(%User{id: user_id}, filter) do
UserFollower
|> where([uf], uf.user_id == ^user_id)
|> join(:inner, [uf], u in assoc(uf, :follower))
Expand All@@ -124,8 +133,14 @@ defmodule GroupherServer.Accounts.Delegate.Fans do
@doc """
get paged followings of a user
"""
@spec fetch_followings(User.t(), map()) :: {:ok, map()} | {:error, String.t()}
def fetch_followings(%User{id: user_id}, filter) do
def paged_followings(%User{id: user_id}, filter, %User{} = cur_user) do
paged_followings(%User{id: user_id}, filter)
|> mark_viewer_follow_status(cur_user)
|> done
end

@spec paged_followings(User.t(), map()) :: {:ok, map()} | {:error, String.t()}
def paged_followings(%User{id: user_id}, filter) do
UserFollowing
|> where([uf], uf.user_id == ^user_id)
|> join(:inner, [uf], u in assoc(uf, :following))
Expand All@@ -140,4 +155,66 @@ defmodule GroupherServer.Accounts.Delegate.Fans do
|> ORM.paginater(~m(page size)a)
|> done()
end

@doc """
mark viewer's follower/followings states
"""
def mark_viewer_follow_status({:ok, %{entries: entries} = paged_users}, cur_user) do
entries = Enum.map(entries, &Map.merge(&1, do_mark_viewer_has_states(&1.id, cur_user)))
Map.merge(paged_users, %{entries: entries})
end

def mark_viewer_follow_status({:error, reason}), do: {:error, reason}

defp do_mark_viewer_has_states(user_id, %User{meta: nil}) do
%{viewer_been_followed: false, viewer_has_followed: false}
end

defp do_mark_viewer_has_states(user_id, %User{meta: meta}) do
%{
viewer_been_followed: Enum.member?(meta.follower_user_ids, user_id),
viewer_has_followed: Enum.member?(meta.following_user_ids, user_id)
}
end

@spec result({:ok, map()}) :: SpecType.done()
defp result({:ok, %{create_follower: user_follower}}) do
User |> ORM.find(user_follower.user_id)
end

defp result({:ok, %{delete_follower: user_follower}}) do
User |> ORM.find(user_follower.user_id)
end

defp result({:ok, %{update_follower_meta: result}}) do
{:ok, result}
end

defp result({:error, :create_follower, %Ecto.Changeset{}, _steps}) do
{:error, [message: "already followed", code: ecode(:already_did)]}
end

defp result({:error, :create_follower, _result, _steps}) do
{:error, [message: "already followed", code: ecode(:already_did)]}
end

defp result({:error, :create_following, _result, _steps}) do
{:error, [message: "follow fails", code: ecode(:react_fails)]}
end

defp result({:error, :delete_follower, _result, _steps}) do
{:error, [message: "already unfollowed", code: ecode(:already_did)]}
end

defp result({:error, :delete_following, _result, _steps}) do
{:error, [message: "unfollow fails", code: ecode(:react_fails)]}
end

defp result({:error, :minus_achievement, _result, _steps}) do
{:error, [message: "follow acieve fails", code: ecode(:react_fails)]}
end

defp result({:error, :add_achievement, _result, _steps}) do
{:error, [message: "follow acieve fails", code: ecode(:react_fails)]}
end
end
49 changes: 45 additions & 4 deletionslib/groupher_server/accounts/delegates/profile.ex
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,22 +6,57 @@ defmodule GroupherServer.Accounts.Delegate.Profile do
import Helper.Utils, only: [done: 1, get_config: 2]
import ShortMaps

alias GroupherServer.{Accounts, CMS, Email, Repo}
alias GroupherServer.{Accounts, CMS, Email, Repo, Statistics}

alias Accounts.{Achievement, GithubUser, User, Social}
alias Helper.{Guardian, ORM, QueryBuilder, RadarSearch}

alias GroupherServer.Accounts.Delegate.Fans
alias Ecto.Multi

@default_subscribed_communities get_config(:general, :default_subscribed_communities)

def read_user(login) when is_binary(login) do
with {:ok, user} <- ORM.read_by(User, %{login: login}, inc: :views) do
case user.contributes do
nil -> assign_default_contributes(user)
_ -> {:ok, user}
end
end
end

def read_user(login, %User{meta: nil}), do: read_user(login)

def read_user(login, %User{} = cur_user) do
with {:ok, user} <- read_user(login) do
# Ta 关注了你
viewer_been_followed = user.id in cur_user.meta.follower_user_ids
# 正在关注
viewer_has_followed = user.id in cur_user.meta.following_user_ids

user =
Map.merge(user, %{
viewer_been_followed: viewer_been_followed,
viewer_has_followed: viewer_has_followed
})

{:ok, user}
end
end

def paged_users(filter, %User{} = user) do
ORM.find_all(User, filter) |> Fans.mark_viewer_follow_status(user) |> done
end

def paged_users(filter) do
ORM.find_all(User, filter)
end

@doc """
update user's profile
"""
def update_profile(%User{} = user, attrs \\ %{}) do
changeset =
user
|> Ecto.Changeset.change(attrs)
changeset = user |> Ecto.Changeset.change(attrs)

changeset
|> update_social_ifneed(user, attrs)
Expand DownExpand Up@@ -257,4 +292,10 @@ defmodule GroupherServer.Accounts.Delegate.Profile do
changeset
end
end

# assign default contributes
defp assign_default_contributes(%User{} = user) do
{:ok, contributes} = Statistics.list_contributes_digest(%User{id: user.id})
ORM.update_embed(user, :contributes, contributes)
end
end
25 changes: 25 additions & 0 deletionslib/groupher_server/accounts/embeds/user_contribute.ex
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
defmodule GroupherServer.Accounts.Embeds.UserContribute do
@moduledoc """
user contribute
"""
use Ecto.Schema
use Accessible
import Ecto.Changeset

alias GroupherServer.Accounts.Embeds

@optional_fields ~w(reported_count)a

embedded_schema do
field(:start_date, :date)
field(:end_date, :date)
field(:total_count, :integer, default: 0)
embeds_many(:records, Embeds.UserContributeRecord, on_replace: :delete)
end

def changeset(struct, params) do
struct
|> cast(params, @optional_fields)
|> cast_embed(:records, with: &Embeds.UserContributeRecord.changeset/2)
end
end
Loading

[8]ページ先頭

©2009-2025 Movatter.jp