{"action":"created","comment":{"url":"https://api.github.com/repos/scrogson/oauth2/pulls/comments/28210571","id":28210571,"diff_hunk":"@@ -0,0 +1,188 @@\n+defmodule OAuth2.Client do\n+  @moduledoc \"\"\"\n+  OAuth2 Client\n+\n+  This module is responsible for building and establishing a request for an\n+  access token.\n+  \"\"\"\n+\n+  @type strategy      :: module\n+  @type client_id     :: binary\n+  @type client_secret :: binary\n+  @type site          :: binary\n+  @type authorize_url :: binary\n+  @type token_url     :: binary\n+  @type token_method  :: :post | :get | atom\n+  @type redirect_uri  :: binary\n+  @type param         :: binary | %{binary => param} | [param]\n+  @type params        :: %{binary => param}\n+  @type headers       :: [{binary, binary}]\n+\n+\n+  @type t :: %__MODULE__{\n+              strategy:      strategy,\n+              client_id:     client_id,\n+              client_secret: client_secret,\n+              site:          site,\n+              authorize_url: authorize_url,\n+              token_url:     token_url,\n+              token_method:  token_method,\n+              params:        params,\n+              headers:       headers,\n+              redirect_uri:  redirect_uri}\n+\n+  defstruct strategy: OAuth2.Strategy.AuthCode,\n+            client_id: \"\",\n+            client_secret: \"\",\n+            site: \"\",\n+            authorize_url: \"/oauth/authorize\",\n+            token_url: \"/oauth/token\",\n+            token_method: :post,\n+            params: %{},\n+            headers: [],\n+            redirect_uri: \"\"\n+\n+  alias OAuth2.Error\n+  alias OAuth2.Client\n+  alias OAuth2.Request\n+  alias OAuth2.Response\n+  alias OAuth2.Strategy\n+  alias OAuth2.AccessToken\n+\n+  @doc \"\"\"\n+  Builds a new OAuth2 client struct using the `opts` provided.\n+\n+  ## Client struct fields\n+\n+  * `strategy` - a module that implements the appropriate OAuth2 strategy,\n+    default `OAuth2.Strategy.AuthCode`\n+  * `client_id` - the client_id for the OAuth2 provider\n+  * `client_secret` - the client_secret for the OAuth2 provider\n+  * `site` - the OAuth2 provider site host\n+  * `authorize_url` - absolute or relative URL path to the authorization endpoint,\n+    default `\"/oauth/authorize\"`\n+  * `token_url` - absolute or relative URL path to the token endpoint,\n+    default `\"/oauth/token\"`\n+  * `token_method` - HTTP method to use to request token (:get or :post),\n+    default `:post`\n+  * `params`: a map of request parameters\n+  * `headers`: a list of request headers\n+  * `redirect_uri`: the URI the provider should redirect to after authorization\n+     or token requests\n+  \"\"\"\n+  @spec new(Keyword.t) :: t\n+  def new(opts), do: struct(__MODULE__, opts)\n+\n+  @doc \"\"\"\n+  Puts the specified `value` in the params for the given `key`.\n+\n+  The key can be a string or an atom, atoms are automatically\n+  convert to strings.\n+  \"\"\"\n+  @spec put_param(t, String.t | atom, any) :: t\n+  def put_param(%Client{params: params} = client, key, value) do\n+    %{client | params: Map.put(params, param_key(key), value)}\n+  end\n+\n+  @doc \"\"\"\n+  Set multiple params in the client in one call.\n+  \"\"\"\n+  @spec merge_params(t, OAuth2.params) :: t\n+  def merge_params(client, params) do\n+    params = Enum.reduce(params, %{}, fn {k,v}, acc ->\n+      Map.put(acc, param_key(k), v)\n+    end)\n+    %{client | params: Map.merge(client.params, params)}\n+  end\n+\n+  @doc \"\"\"\n+  Adds a new header `key` if not present, otherwise replaces the\n+  previous value of that header with `value`.\n+  \"\"\"\n+  @spec put_header(t, binary, binary) :: t\n+  def put_header(%Client{headers: headers} = client, key, value) when\n+    is_binary(key) and is_binary(value) do\n+    %{client | headers: List.keystore(headers, key, 0, {key, value})}\n+  end\n+\n+  @doc \"\"\"\n+  Set multiple headers in the client in one call.\n+  \"\"\"\n+  @spec put_headers(t, list) :: t\n+  def put_headers(%Client{} = client, []), do: client\n+  def put_headers(%Client{} = client, [{k,v}|rest]) do\n+    client |> put_header(k,v) |> put_headers(rest)","path":"lib/oauth2/client.ex","position":114,"original_position":114,"commit_id":"bee25b05d3693da95ddc5249aad62ad939f11b49","original_commit_id":"bee25b05d3693da95ddc5249aad62ad939f11b49","user":{"login":"knewter","id":3829,"avatar_url":"https://avatars.githubusercontent.com/u/3829?v=3","gravatar_id":"","url":"https://api.github.com/users/knewter","html_url":"https://github.com/knewter","followers_url":"https://api.github.com/users/knewter/followers","following_url":"https://api.github.com/users/knewter/following{/other_user}","gists_url":"https://api.github.com/users/knewter/gists{/gist_id}","starred_url":"https://api.github.com/users/knewter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/knewter/subscriptions","organizations_url":"https://api.github.com/users/knewter/orgs","repos_url":"https://api.github.com/users/knewter/repos","events_url":"https://api.github.com/users/knewter/events{/privacy}","received_events_url":"https://api.github.com/users/knewter/received_events","type":"User","site_admin":false},"body":"really enjoyed this line","created_at":"2015-04-13T01:36:21Z","updated_at":"2015-04-13T01:36:21Z","html_url":"https://github.com/scrogson/oauth2/pull/13#discussion_r28210571","pull_request_url":"https://api.github.com/repos/scrogson/oauth2/pulls/13","_links":{"self":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/comments/28210571"},"html":{"href":"https://github.com/scrogson/oauth2/pull/13#discussion_r28210571"},"pull_request":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/13"}}},"pull_request":{"url":"https://api.github.com/repos/scrogson/oauth2/pulls/13","id":33130120,"html_url":"https://github.com/scrogson/oauth2/pull/13","diff_url":"https://github.com/scrogson/oauth2/pull/13.diff","patch_url":"https://github.com/scrogson/oauth2/pull/13.patch","issue_url":"https://api.github.com/repos/scrogson/oauth2/issues/13","number":13,"state":"open","locked":false,"title":"Overhaul the API","user":{"login":"scrogson","id":53274,"avatar_url":"https://avatars.githubusercontent.com/u/53274?v=3","gravatar_id":"","url":"https://api.github.com/users/scrogson","html_url":"https://github.com/scrogson","followers_url":"https://api.github.com/users/scrogson/followers","following_url":"https://api.github.com/users/scrogson/following{/other_user}","gists_url":"https://api.github.com/users/scrogson/gists{/gist_id}","starred_url":"https://api.github.com/users/scrogson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scrogson/subscriptions","organizations_url":"https://api.github.com/users/scrogson/orgs","repos_url":"https://api.github.com/users/scrogson/repos","events_url":"https://api.github.com/users/scrogson/events{/privacy}","received_events_url":"https://api.github.com/users/scrogson/received_events","type":"User","site_admin":false},"body":null,"created_at":"2015-04-13T00:57:33Z","updated_at":"2015-04-13T01:36:21Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cdd56aa3c4ecf836984c05ca62be980e19e2580c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/scrogson/oauth2/pulls/13/commits","review_comments_url":"https://api.github.com/repos/scrogson/oauth2/pulls/13/comments","review_comment_url":"https://api.github.com/repos/scrogson/oauth2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/scrogson/oauth2/issues/13/comments","statuses_url":"https://api.github.com/repos/scrogson/oauth2/statuses/bee25b05d3693da95ddc5249aad62ad939f11b49","head":{"label":"scrogson:refactor","ref":"refactor","sha":"bee25b05d3693da95ddc5249aad62ad939f11b49","user":{"login":"scrogson","id":53274,"avatar_url":"https://avatars.githubusercontent.com/u/53274?v=3","gravatar_id":"","url":"https://api.github.com/users/scrogson","html_url":"https://github.com/scrogson","followers_url":"https://api.github.com/users/scrogson/followers","following_url":"https://api.github.com/users/scrogson/following{/other_user}","gists_url":"https://api.github.com/users/scrogson/gists{/gist_id}","starred_url":"https://api.github.com/users/scrogson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scrogson/subscriptions","organizations_url":"https://api.github.com/users/scrogson/orgs","repos_url":"https://api.github.com/users/scrogson/repos","events_url":"https://api.github.com/users/scrogson/events{/privacy}","received_events_url":"https://api.github.com/users/scrogson/received_events","type":"User","site_admin":false},"repo":{"id":20585853,"name":"oauth2","full_name":"scrogson/oauth2","owner":{"login":"scrogson","id":53274,"avatar_url":"https://avatars.githubusercontent.com/u/53274?v=3","gravatar_id":"","url":"https://api.github.com/users/scrogson","html_url":"https://github.com/scrogson","followers_url":"https://api.github.com/users/scrogson/followers","following_url":"https://api.github.com/users/scrogson/following{/other_user}","gists_url":"https://api.github.com/users/scrogson/gists{/gist_id}","starred_url":"https://api.github.com/users/scrogson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scrogson/subscriptions","organizations_url":"https://api.github.com/users/scrogson/orgs","repos_url":"https://api.github.com/users/scrogson/repos","events_url":"https://api.github.com/users/scrogson/events{/privacy}","received_events_url":"https://api.github.com/users/scrogson/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/scrogson/oauth2","description":"An Elixir OAuth 2.0 Client Library","fork":false,"url":"https://api.github.com/repos/scrogson/oauth2","forks_url":"https://api.github.com/repos/scrogson/oauth2/forks","keys_url":"https://api.github.com/repos/scrogson/oauth2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scrogson/oauth2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scrogson/oauth2/teams","hooks_url":"https://api.github.com/repos/scrogson/oauth2/hooks","issue_events_url":"https://api.github.com/repos/scrogson/oauth2/issues/events{/number}","events_url":"https://api.github.com/repos/scrogson/oauth2/events","assignees_url":"https://api.github.com/repos/scrogson/oauth2/assignees{/user}","branches_url":"https://api.github.com/repos/scrogson/oauth2/branches{/branch}","tags_url":"https://api.github.com/repos/scrogson/oauth2/tags","blobs_url":"https://api.github.com/repos/scrogson/oauth2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scrogson/oauth2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scrogson/oauth2/git/refs{/sha}","trees_url":"https://api.github.com/repos/scrogson/oauth2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scrogson/oauth2/statuses/{sha}","languages_url":"https://api.github.com/repos/scrogson/oauth2/languages","stargazers_url":"https://api.github.com/repos/scrogson/oauth2/stargazers","contributors_url":"https://api.github.com/repos/scrogson/oauth2/contributors","subscribers_url":"https://api.github.com/repos/scrogson/oauth2/subscribers","subscription_url":"https://api.github.com/repos/scrogson/oauth2/subscription","commits_url":"https://api.github.com/repos/scrogson/oauth2/commits{/sha}","git_commits_url":"https://api.github.com/repos/scrogson/oauth2/git/commits{/sha}","comments_url":"https://api.github.com/repos/scrogson/oauth2/comments{/number}","issue_comment_url":"https://api.github.com/repos/scrogson/oauth2/issues/comments{/number}","contents_url":"https://api.github.com/repos/scrogson/oauth2/contents/{+path}","compare_url":"https://api.github.com/repos/scrogson/oauth2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scrogson/oauth2/merges","archive_url":"https://api.github.com/repos/scrogson/oauth2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scrogson/oauth2/downloads","issues_url":"https://api.github.com/repos/scrogson/oauth2/issues{/number}","pulls_url":"https://api.github.com/repos/scrogson/oauth2/pulls{/number}","milestones_url":"https://api.github.com/repos/scrogson/oauth2/milestones{/number}","notifications_url":"https://api.github.com/repos/scrogson/oauth2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scrogson/oauth2/labels{/name}","releases_url":"https://api.github.com/repos/scrogson/oauth2/releases{/id}","created_at":"2014-06-07T04:55:22Z","updated_at":"2015-04-11T20:53:35Z","pushed_at":"2015-04-13T00:57:33Z","git_url":"git://github.com/scrogson/oauth2.git","ssh_url":"git@github.com:scrogson/oauth2.git","clone_url":"https://github.com/scrogson/oauth2.git","svn_url":"https://github.com/scrogson/oauth2","homepage":"","size":382,"stargazers_count":18,"watchers_count":18,"language":"Elixir","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":2,"forks":15,"open_issues":2,"watchers":18,"default_branch":"master"}},"base":{"label":"scrogson:master","ref":"master","sha":"eee9161642848128cf2b93b1f85e0b6f198f1261","user":{"login":"scrogson","id":53274,"avatar_url":"https://avatars.githubusercontent.com/u/53274?v=3","gravatar_id":"","url":"https://api.github.com/users/scrogson","html_url":"https://github.com/scrogson","followers_url":"https://api.github.com/users/scrogson/followers","following_url":"https://api.github.com/users/scrogson/following{/other_user}","gists_url":"https://api.github.com/users/scrogson/gists{/gist_id}","starred_url":"https://api.github.com/users/scrogson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scrogson/subscriptions","organizations_url":"https://api.github.com/users/scrogson/orgs","repos_url":"https://api.github.com/users/scrogson/repos","events_url":"https://api.github.com/users/scrogson/events{/privacy}","received_events_url":"https://api.github.com/users/scrogson/received_events","type":"User","site_admin":false},"repo":{"id":20585853,"name":"oauth2","full_name":"scrogson/oauth2","owner":{"login":"scrogson","id":53274,"avatar_url":"https://avatars.githubusercontent.com/u/53274?v=3","gravatar_id":"","url":"https://api.github.com/users/scrogson","html_url":"https://github.com/scrogson","followers_url":"https://api.github.com/users/scrogson/followers","following_url":"https://api.github.com/users/scrogson/following{/other_user}","gists_url":"https://api.github.com/users/scrogson/gists{/gist_id}","starred_url":"https://api.github.com/users/scrogson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/scrogson/subscriptions","organizations_url":"https://api.github.com/users/scrogson/orgs","repos_url":"https://api.github.com/users/scrogson/repos","events_url":"https://api.github.com/users/scrogson/events{/privacy}","received_events_url":"https://api.github.com/users/scrogson/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/scrogson/oauth2","description":"An Elixir OAuth 2.0 Client Library","fork":false,"url":"https://api.github.com/repos/scrogson/oauth2","forks_url":"https://api.github.com/repos/scrogson/oauth2/forks","keys_url":"https://api.github.com/repos/scrogson/oauth2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/scrogson/oauth2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/scrogson/oauth2/teams","hooks_url":"https://api.github.com/repos/scrogson/oauth2/hooks","issue_events_url":"https://api.github.com/repos/scrogson/oauth2/issues/events{/number}","events_url":"https://api.github.com/repos/scrogson/oauth2/events","assignees_url":"https://api.github.com/repos/scrogson/oauth2/assignees{/user}","branches_url":"https://api.github.com/repos/scrogson/oauth2/branches{/branch}","tags_url":"https://api.github.com/repos/scrogson/oauth2/tags","blobs_url":"https://api.github.com/repos/scrogson/oauth2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/scrogson/oauth2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/scrogson/oauth2/git/refs{/sha}","trees_url":"https://api.github.com/repos/scrogson/oauth2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/scrogson/oauth2/statuses/{sha}","languages_url":"https://api.github.com/repos/scrogson/oauth2/languages","stargazers_url":"https://api.github.com/repos/scrogson/oauth2/stargazers","contributors_url":"https://api.github.com/repos/scrogson/oauth2/contributors","subscribers_url":"https://api.github.com/repos/scrogson/oauth2/subscribers","subscription_url":"https://api.github.com/repos/scrogson/oauth2/subscription","commits_url":"https://api.github.com/repos/scrogson/oauth2/commits{/sha}","git_commits_url":"https://api.github.com/repos/scrogson/oauth2/git/commits{/sha}","comments_url":"https://api.github.com/repos/scrogson/oauth2/comments{/number}","issue_comment_url":"https://api.github.com/repos/scrogson/oauth2/issues/comments{/number}","contents_url":"https://api.github.com/repos/scrogson/oauth2/contents/{+path}","compare_url":"https://api.github.com/repos/scrogson/oauth2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/scrogson/oauth2/merges","archive_url":"https://api.github.com/repos/scrogson/oauth2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/scrogson/oauth2/downloads","issues_url":"https://api.github.com/repos/scrogson/oauth2/issues{/number}","pulls_url":"https://api.github.com/repos/scrogson/oauth2/pulls{/number}","milestones_url":"https://api.github.com/repos/scrogson/oauth2/milestones{/number}","notifications_url":"https://api.github.com/repos/scrogson/oauth2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/scrogson/oauth2/labels{/name}","releases_url":"https://api.github.com/repos/scrogson/oauth2/releases{/id}","created_at":"2014-06-07T04:55:22Z","updated_at":"2015-04-11T20:53:35Z","pushed_at":"2015-04-13T00:57:33Z","git_url":"git://github.com/scrogson/oauth2.git","ssh_url":"git@github.com:scrogson/oauth2.git","clone_url":"https://github.com/scrogson/oauth2.git","svn_url":"https://github.com/scrogson/oauth2","homepage":"","size":382,"stargazers_count":18,"watchers_count":18,"language":"Elixir","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":2,"forks":15,"open_issues":2,"watchers":18,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/13"},"html":{"href":"https://github.com/scrogson/oauth2/pull/13"},"issue":{"href":"https://api.github.com/repos/scrogson/oauth2/issues/13"},"comments":{"href":"https://api.github.com/repos/scrogson/oauth2/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/scrogson/oauth2/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/scrogson/oauth2/statuses/bee25b05d3693da95ddc5249aad62ad939f11b49"}}}}