@@ -2,35 +2,103 @@ defmodule CodeCorps.Accounts do
22 @ moduledoc ~S"""
33 Main entry-point for managing accounts.
44
5- All actions to acounts should go through here.
5+ All actions to accounts should go through here.
66 """
77
88 alias CodeCorps . {
9+ Accounts.Changesets ,
10+ Comment ,
911 GitHub.Adapters ,
12+ GithubAppInstallation ,
1013 User ,
11- Repo
14+ Repo ,
15+ Task
1216 }
13- alias Ecto.Changeset
17+ alias Ecto . { Changeset , Multi }
18+
19+ import Ecto.Query
1420
1521 @ doc ~S"""
1622 Creates a user record using attributes from a GitHub payload.
1723 """
1824 @ spec create_from_github ( map ) :: { :ok , User . t } | { :error , Changeset . t }
1925 def create_from_github ( % { } = attrs ) do
2026 % User { }
21- |> create_from_github_changeset ( attrs )
27+ |> Changesets . create_from_github_changeset ( attrs )
2228 |> Repo . insert
2329 end
2430
2531 @ doc ~S"""
26- Casts a changeset used for creating a user account from a github user payload
32+ Updates a user record using attributes from a GitHub payload along with the
33+ access token.
2734 """
28- @ spec create_from_github_changeset ( struct , map ) :: Changeset . t
29- def create_from_github_changeset ( struct , % { } = params ) do
30- struct
31- |> Changeset . change ( params |> Adapters.User . from_github_user ( ) )
32- |> Changeset . put_change ( :context , "github" )
33- |> Changeset . unique_constraint ( :email )
34- |> Changeset . validate_inclusion ( :type , [ "bot" , "user" ] )
35+ @ spec update_from_github_oauth ( User . t , map , String . t ) :: { :ok , User . t } | { :error , Changeset . t }
36+ def update_from_github_oauth ( % User { } = user , % { } = params , access_token ) do
37+ params =
38+ params
39+ |> Adapters.User . from_github_user ( )
40+ |> Map . put ( :github_auth_token , access_token )
41+
42+ changeset = user |> Changesets . update_from_github_oauth_changeset ( params )
43+
44+ multi =
45+ Multi . new
46+ |> Multi . update ( :user , changeset )
47+ |> Multi . run ( :installations , fn % { user: % User { } = user } -> user |> associate_installations ( ) end )
48+ |> Multi . run ( :tasks , fn % { user: % User { } = user } -> user |> associate_tasks ( ) end )
49+ |> Multi . run ( :comments , fn % { user: % User { } = user } -> user |> associate_comments ( ) end )
50+
51+ case Repo . transaction ( multi ) do
52+ { :ok , % { user: % User { } = user , installations: installations } } ->
53+ { :ok , user |> Map . put ( :github_app_installations , installations ) }
54+ { :error , :user , % Changeset { } = changeset , _actions_done } ->
55+ { :error , changeset }
56+ end
57+ end
58+
59+ @ spec associate_installations ( User . t ) :: { :ok , list ( GithubAppInstallation . t ) }
60+ defp associate_installations ( % User { id: user_id , github_id: github_id } ) do
61+ updates = [ set: [ user_id: user_id ] ]
62+ update_options = [ returning: true ]
63+
64+ GithubAppInstallation
65+ |> where ( [ i ] , i . sender_github_id == ^ github_id )
66+ |> where ( [ i ] , is_nil ( i . user_id ) )
67+ |> Repo . update_all ( updates , update_options )
68+ |> ( fn { _count , installations } -> { :ok , installations } end ) . ( )
69+ end
70+
71+ @ spec associate_tasks ( User . t ) :: { :ok , list ( Task . t ) }
72+ defp associate_tasks ( % User { id: user_id , github_id: github_id } ) do
73+ updates = [ set: [ user_id: user_id ] ]
74+ update_options = [ returning: true ]
75+
76+ existing_user_ids =
77+ User
78+ |> where ( github_id: ^ github_id )
79+ |> select ( [ u ] , u . id )
80+ |> Repo . all
81+
82+ Task
83+ |> where ( [ t ] , t . user_id in ^ existing_user_ids )
84+ |> Repo . update_all ( updates , update_options )
85+ |> ( fn { _count , tasks } -> { :ok , tasks } end ) . ( )
86+ end
87+
88+ @ spec associate_comments ( User . t ) :: { :ok , list ( Comment . t ) }
89+ defp associate_comments ( % User { id: user_id , github_id: github_id } ) do
90+ updates = [ set: [ user_id: user_id ] ]
91+ update_options = [ returning: true ]
92+
93+ existing_user_ids =
94+ User
95+ |> where ( github_id: ^ github_id )
96+ |> select ( [ u ] , u . id )
97+ |> Repo . all
98+
99+ Comment
100+ |> where ( [ c ] , c . user_id in ^ existing_user_ids )
101+ |> Repo . update_all ( updates , update_options )
102+ |> ( fn { _count , comments } -> { :ok , comments } end ) . ( )
35103 end
36104end
0 commit comments