diff --git a/USAGE.md b/USAGE.md index 9af08a101..f951fe726 100644 --- a/USAGE.md +++ b/USAGE.md @@ -77,7 +77,7 @@ You can register for a Stripe account here: [https://dashboard.stripe.com/regist In your `.env` you should have a `STRIPE_SECRET_KEY` and `STRIPE_PLATFORM_CLIENT_ID`. - `STRIPE_SECRET_KEY` should be set to your "Test Secret Key" from the [API Keys section of your Stripe dashboard](https://dashboard.stripe.com/account/apikeys). -- `STRIPE_PLATFORM_CLIENT_ID` should be set to "Development `client_id`" key from the [Connect section of your Stripe dashboard](https://dashboard.stripe.com/account/applications/settings). You'll want to set the redirect URI to `http://localhost:4200/oauth/stripe`. +- `STRIPE_PLATFORM_CLIENT_ID` should be set to "Development `client_id`" key from the [Connect section of your Stripe dashboard](https://dashboard.stripe.com/account/applications/settings). ### Pushing changes diff --git a/blueprint/api.apib b/blueprint/api.apib index ade08a79d..5410e6fd1 100644 --- a/blueprint/api.apib +++ b/blueprint/api.apib @@ -893,26 +893,6 @@ This resource identifies a relationship between a Project and a Skill. For examp + Attributes (Project Response) -### Get Stripe authorization [GET /projects/{id}/stripe-auth] - -This endpoint allows you to get a Stripe Connect authorization URL used for creating a Stripe Connect account for the given project. - -See https://stripe.com/docs/connect/reference#get-authorize - -The URL includes a `state` CSRF token which is a Guardian generated JSON Web Token which contains the project's ID. This JWT will be used when the -+ Parameters - - + id (number, required) -user returns to Code Corps in order to associate Stripe's `code` with the project that initiated the Stripe Connect authorization. - -+ Response 200 (application/vnd.api+json; charset=utf-8) - - + Attributes (Stripe Auth Response) - -+ Response 401 (application/vnd.api+json; charset=utf-8) - - + Attributes (JSON Web Token Invalid Response) - ### Update a project [PATCH] + Request @@ -2596,20 +2576,6 @@ This endpoint allows you to check whether a username is valid (by running a vali + data(Slugged Route User Resource) + include JSON API Version -## Stripe Auth Attributes (object) -+ url: `https://connect.stripe.com/oauth/authorize?response_type=code&scope=read_write&client_id=ca_APP_CLIENT_ID&state=JWT_STRING` (string, required) - -## Stripe Auth Resource (object) -+ include Stripe Auth Resource Identifier -+ attributes(Stripe Auth Attributes) - -## Stripe Auth Resource Identifier (object) -+ id: `1` (string, required) -+ type: `stripe-auth` (string, required) - -## Stripe Auth Response (object) -+ data(Stripe Auth Resource) - ## Stripe Connect Account Attributes (object) + `business-name`: `Stripe.com` (string) - The publicly visible name of the business + `business-url`: null (string) - The publicly visible website of the business diff --git a/config/dev.exs b/config/dev.exs index ccb51efa8..ced6bfde6 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -50,7 +50,6 @@ config :code_corps, :analytics, CodeCorps.Analytics.InMemoryAPI # Configures stripe for dev mode config :code_corps, :stripe, Stripe config :code_corps, :stripe_env, :dev -config :code_corps, :stripe_redirect_uri, "http://localhost:4200/oauth/stripe" config :sentry, environment_name: Mix.env || :dev diff --git a/config/prod.exs b/config/prod.exs index a8cfd0a53..ac04d691b 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -49,7 +49,6 @@ config :code_corps, :analytics, CodeCorps.Analytics.SegmentAPI # Configures stripe for production config :code_corps, :stripe, Stripe config :code_corps, :stripe_env, :prod -config :code_corps, :stripe_redirect_uri, "https://www.codecorps.org/oauth/stripe" config :sentry, environment_name: Mix.env || :prod diff --git a/config/remote-development.exs b/config/remote-development.exs index 6b4dedc97..d105d2887 100644 --- a/config/remote-development.exs +++ b/config/remote-development.exs @@ -36,7 +36,6 @@ config :logger, level: :info # Configures stripe for remote dev config :code_corps, :stripe, Stripe config :code_corps, :stripe_env, :remote_dev -config :code_corps, :stripe_redirect_uri, "http://www.pbqrpbecf-qri.org/oauth/stripe" config :code_corps, CodeCorps.Mailer, adapter: Bamboo.LocalAdapter diff --git a/config/staging.exs b/config/staging.exs index e5f3357e4..db2b8cb15 100644 --- a/config/staging.exs +++ b/config/staging.exs @@ -51,7 +51,6 @@ config :sentry, # Configures stripe for staging config :code_corps, :stripe, Stripe config :code_corps, :stripe_env, :staging -config :code_corps, :stripe_redirect_uri, "http://www.pbqrpbecf.org/oauth/stripe" config :code_corps, CodeCorps.Mailer, adapter: Bamboo.LocalAdapter diff --git a/config/test.exs b/config/test.exs index 6101c7244..be8c2def0 100644 --- a/config/test.exs +++ b/config/test.exs @@ -33,7 +33,6 @@ config :code_corps, :analytics, CodeCorps.Analytics.TestAPI # Configures stripe for test mode config :code_corps, :stripe, CodeCorps.StripeTesting config :code_corps, :stripe_env, :test -config :code_corps, :stripe_redirect_uri, "http://localhost:4200/oauth/stripe" config :code_corps, :icon_color_generator, CodeCorps.RandomIconColor.TestGenerator diff --git a/lib/code_corps/stripe_service/stripe_connect_account.ex b/lib/code_corps/stripe_service/stripe_connect_account.ex index db16ee8d5..0cf599661 100644 --- a/lib/code_corps/stripe_service/stripe_connect_account.ex +++ b/lib/code_corps/stripe_service/stripe_connect_account.ex @@ -1,12 +1,12 @@ defmodule CodeCorps.StripeService.StripeConnectAccountService do alias CodeCorps.StripeService.Adapters.StripeConnectAccountAdapter - alias Stripe.Connect.OAuth.TokenResponse @api Application.get_env(:code_corps, :stripe) - def create(%{"access_code" => code, "organization_id" => _organization_id} = attributes) do - with {:ok, %TokenResponse{stripe_user_id: account_id}} <- @api.Connect.OAuth.token(code), - {:ok, account} <- @api.Account.retrieve(account_id), + # TODO: Replace with code that implements issue #564 + + def create(%{"country" => country_code, "organization_id" => organization_id} = attributes) do + with {:ok, %Stripe.Account{} = account} <- @api.Account.create(%{country: country_code, managed: true}), {:ok, params} <- StripeConnectAccountAdapter.to_params(account, attributes) do %CodeCorps.StripeConnectAccount{} diff --git a/lib/code_corps/stripe_testing/account.ex b/lib/code_corps/stripe_testing/account.ex index c37bc28e2..88df1225f 100644 --- a/lib/code_corps/stripe_testing/account.ex +++ b/lib/code_corps/stripe_testing/account.ex @@ -1,9 +1,13 @@ defmodule CodeCorps.StripeTesting.Account do + def create(_map) do + {:ok, do_create} + end + def retrieve(_id) do - {:ok, do_retrieve} + {:ok, do_create} end - defp do_retrieve do + defp do_create do %Stripe.Account{ business_name: "Code Corps PBC", business_primary_color: nil, diff --git a/lib/code_corps/stripe_testing/connect/oauth.ex b/lib/code_corps/stripe_testing/connect/oauth.ex deleted file mode 100644 index cb62e0955..000000000 --- a/lib/code_corps/stripe_testing/connect/oauth.ex +++ /dev/null @@ -1,17 +0,0 @@ -defmodule CodeCorps.StripeTesting.Connect.OAuth do - def token(_map) do - {:ok, do_token} - end - - def do_token do - %Stripe.Connect.OAuth.TokenResponse{ - access_token: "sk_test_123", - livemode: false, - refresh_token: "rt_123", - scope: "read_write", - stripe_publishable_key: "pk_test_123", - stripe_user_id: "acct_123", - token_type: "bearer" - } - end -end diff --git a/mix.lock b/mix.lock index b39cf1524..db0df1805 100644 --- a/mix.lock +++ b/mix.lock @@ -56,6 +56,7 @@ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}, "stripe_eventex": {:hex, :stripe_eventex, "1.0.0", "782016598b751c0fdb5489038c92c30a5aab034636d0d9d3a486f75a01fbf0b6", [:mix], [{:cowboy, "~> 1.0.0", [hex: :cowboy, optional: false]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}, {:poison, "~> 2.0", [hex: :poison, optional: false]}]}, "stripity_stripe": {:hex, :stripity_stripe, "2.0.0-alpha.5", "ba6d4ffc6251029135c76e9c6e2dd77580713f5c6833fb82da708336023bbfa2", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, optional: false]}]}, + "timber": {:hex, :timber, "0.4.7", "df3fcd79bcb4eb4b53874d906ef5f3a212937b4bc7b7c5b244745202cc389443", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, optional: true]}, {:phoenix, "~> 1.2", [hex: :phoenix, optional: true]}, {:plug, "~> 1.2", [hex: :plug, optional: true]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, optional: false]}]}, "timex": {:hex, :timex, "3.1.5", "413d6d8d6f0162a5d47080cb8ca520d790184ac43e097c95191c7563bf25b428", [:mix], [{:combine, "~> 0.7", [hex: :combine, optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, optional: false]}]}, "timex_ecto": {:hex, :timex_ecto, "3.0.5", "3ec6c25e10d2c0020958e5df64d2b5e690e441faa2c2259da8bc6bd3d7f39256", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, optional: false]}, {:timex, "~> 3.0", [hex: :timex, optional: false]}]}, "tzdata": {:hex, :tzdata, "0.5.9", "575be217b039057a47e133b72838cbe104fb5329b19906ea4e66857001c37edb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}, diff --git a/test/controllers/stripe_auth_controller_test.exs b/test/controllers/stripe_auth_controller_test.exs deleted file mode 100644 index eeee39907..000000000 --- a/test/controllers/stripe_auth_controller_test.exs +++ /dev/null @@ -1,46 +0,0 @@ -defmodule CodeCorps.StripeAuthControllerTest do - use CodeCorps.ApiCase - - describe "stripe_auth" do - @tag :requires_env - @tag :authenticated - test "renders the Stripe Connect button URL when authorized", %{conn: conn, current_user: current_user} do - organization = insert(:organization) - insert(:organization_membership, role: "owner", member: current_user, organization: organization) - project = insert(:project, organization: organization) - - conn = get conn, stripe_auth_path(conn, :stripe_auth, project) - assert json_response(conn, 200)["data"]["attributes"]["url"] - end - - @tag :requires_env - test "renders 401 when not authenticated", %{conn: conn} do - project = insert(:project) - - conn = get conn, stripe_auth_path(conn, :stripe_auth, project) - assert json_response(conn, 401) - end - - @tag :requires_env - @tag :authenticated - test "renders a 403 when not authorized", %{conn: conn} do - project = insert(:project) - - conn = get conn, stripe_auth_path(conn, :stripe_auth, project) - assert json_response(conn, 403) - end - - @tag :authenticated - test "sets redirect_uri from environment", %{conn: conn, current_user: current_user} do - Application.put_env(:code_corps, :stripe_redirect_uri, "https://example.com") - organization = insert(:organization) - insert(:organization_membership, role: "owner", member: current_user, organization: organization) - project = insert(:project, organization: organization) - - conn = get conn, stripe_auth_path(conn, :stripe_auth, project) - url = json_response(conn, 200)["data"]["attributes"]["url"] - query = url |> URI.decode_query - assert query["redirect_uri"] == "https://example.com" - end - end -end diff --git a/test/policies/project_policy_test.exs b/test/policies/project_policy_test.exs index e0cbf4933..45ba01807 100644 --- a/test/policies/project_policy_test.exs +++ b/test/policies/project_policy_test.exs @@ -1,7 +1,7 @@ defmodule CodeCorps.ProjectPolicyTest do use CodeCorps.PolicyCase - import CodeCorps.ProjectPolicy, only: [create?: 2, update?: 2, stripe_auth?: 2] + import CodeCorps.ProjectPolicy, only: [create?: 2, update?: 2] import CodeCorps.Project, only: [create_changeset: 2] alias CodeCorps.Project @@ -119,61 +119,4 @@ defmodule CodeCorps.ProjectPolicyTest do assert update?(user, project) end end - - describe "stripe_auth?" do - test "returns true when user is an admin" do - user = build(:user, admin: true) - project = build(:project) - - assert stripe_auth?(user, project) - end - - test "returns false when user is not member of organization" do - user = insert(:user) - organization = insert(:organization) - project = insert(:project, organization: organization) - - refute stripe_auth?(user, project) - end - - test "returns false when user is pending member of organization" do - user = insert(:user) - organization = insert(:organization) - project = insert(:project, organization: organization) - - insert(:organization_membership, role: "pending", member: user, organization: organization) - - refute stripe_auth?(user, project) - end - - test "returns false when user is contributor of organization" do - user = insert(:user) - organization = insert(:organization) - project = insert(:project, organization: organization) - - insert(:organization_membership, role: "contributor", member: user, organization: organization) - - refute stripe_auth?(user, project) - end - - test "returns false when user is admin of organization" do - user = insert(:user) - organization = insert(:organization) - project = insert(:project, organization: organization) - - insert(:organization_membership, role: "admin", member: user, organization: organization) - - refute stripe_auth?(user, project) - end - - test "returns false when user is owner of organization" do - user = insert(:user) - organization = insert(:organization) - project = insert(:project, organization: organization) - - insert(:organization_membership, role: "owner", member: user, organization: organization) - - assert stripe_auth?(user, project) - end - end end diff --git a/web/controllers/stripe_auth_controller.ex b/web/controllers/stripe_auth_controller.ex deleted file mode 100644 index df482863f..000000000 --- a/web/controllers/stripe_auth_controller.ex +++ /dev/null @@ -1,32 +0,0 @@ -defmodule CodeCorps.StripeAuthController do - use CodeCorps.Web, :controller - - alias CodeCorps.Project - alias CodeCorps.Repo - alias CodeCorps.StripeAuth - - plug :load_and_authorize_resource, model: Project, only: [:stripe_auth] - - # We're using `stripe_auth` instead of `show` to use the Project - # policy for authorization - def stripe_auth(conn, %{"id" => project_id}) do - user = conn.assigns[:current_user] - - project = - Project - |> Repo.get(project_id) - |> Repo.preload([:organization]) - - case StripeAuth.authorize_url(user, project) do - {:ok, url} -> - stripe_auth = %StripeAuth{url: url} - - conn - |> render(:show, data: stripe_auth) - {:error, reason} -> - conn - |> put_status(:unauthorized) - |> render("error.json", message: reason) - end - end -end diff --git a/web/models/abilities.ex b/web/models/abilities.ex index c96a79f1e..781ad9d12 100644 --- a/web/models/abilities.ex +++ b/web/models/abilities.ex @@ -84,9 +84,6 @@ defmodule Canary.Abilities do def can?(%User{} = user, :create, %Changeset{data: %Project{}} = changeset), do: ProjectPolicy.create?(user, changeset) def can?(%User{} = user, :update, %Project{} = project), do: ProjectPolicy.update?(user, project) - # Policy for StripeAuthController - def can?(%User{} = user, :stripe_auth, %Project{} = project), do: ProjectPolicy.stripe_auth?(user, project) - def can?(%User{} = user, :create, %Changeset{data: %ProjectCategory{}} = changeset), do: ProjectCategoryPolicy.create?(user, changeset) def can?(%User{} = user, :delete, %ProjectCategory{} = project_category), do: ProjectCategoryPolicy.delete?(user, project_category) diff --git a/web/models/stripe_auth.ex b/web/models/stripe_auth.ex deleted file mode 100644 index 4a528e116..000000000 --- a/web/models/stripe_auth.ex +++ /dev/null @@ -1,55 +0,0 @@ -defmodule CodeCorps.StripeAuth do - @moduledoc """ - Provides a virtual resource for data needed for Stripe Connect OAuth flows. - """ - - use Ecto.Schema - - alias CodeCorps.Organization - alias CodeCorps.Project - - schema "" do - field :url, :string, virtual: true - end - - @doc """ - Generates the URL for a Stripe Connect button for a given project. - - The URL includes a `state` CSRF token which is a Guardian generated - JWT which contains the project's ID. - - Returns either an `:ok` or `:error` tuple. - """ - def authorize_url(user, %Project{organization: %Organization{} = organization} = project) do - case Guardian.encode_and_sign(project, :token) do - {:ok, token, _claims} -> - url = - organization - |> url_params(user, token) - |> Stripe.Connect.OAuth.authorize_url() - {:ok, url} - {:error, reason} -> - {:error, reason} - end - end - - defp url_params(organization, user, token) do - %{ - state: token, - redirect_uri: redirect_uri, - stripe_user: %{ - "business_name" => organization.name, - "email" => user.email, - "first_name" => user.first_name, - "last_name" => user.last_name, - "product_category" => "software", - "product_description" => organization.name <> " accepts donations on the Code Corps platform in order to build and sustain open source software for public good. Donations usually happen once a month, although the frequency may vary.", - "url" => "https://www.codecorps.org/" <> organization.slug - } - } - end - - defp redirect_uri do - Application.get_env(:code_corps, :stripe_redirect_uri) - end -end diff --git a/web/policies/project_policy.ex b/web/policies/project_policy.ex index cd796b068..f2603c0fc 100644 --- a/web/policies/project_policy.ex +++ b/web/policies/project_policy.ex @@ -14,7 +14,4 @@ defmodule CodeCorps.ProjectPolicy do def update?(%User{admin: true}, %Project{}), do: true def update?(%User{} = user, %Project{} = project), do: project |> get_membership(user) |> get_role |> admin_or_higher? - - def stripe_auth?(%User{admin: true}, %Project{}), do: true - def stripe_auth?(%User{} = user, %Project{} = project), do: project |> get_membership(user) |> get_role |> owner? end diff --git a/web/router.ex b/web/router.ex index 8bf1b0ea5..086fe8884 100644 --- a/web/router.ex +++ b/web/router.ex @@ -63,7 +63,6 @@ defmodule CodeCorps.Router do resources "/organization-memberships", OrganizationMembershipController, only: [:create, :update, :delete] resources "/previews", PreviewController, only: [:create] resources "/projects", ProjectController, only: [:create, :update] - get "/projects/:id/stripe-auth", StripeAuthController, :stripe_auth resources "/project-categories", ProjectCategoryController, only: [:create, :delete] resources "/project-skills", ProjectSkillController, only: [:create, :delete] resources "/roles", RoleController, only: [:create] diff --git a/web/views/stripe_auth_view.ex b/web/views/stripe_auth_view.ex deleted file mode 100644 index e2924b24b..000000000 --- a/web/views/stripe_auth_view.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule CodeCorps.StripeAuthView do - use CodeCorps.Web, :view - use JaSerializer.PhoenixView - - attributes [:url] - - @doc """ - Since this view does not represent a record, the `id` is manually - set to `"1"`. - """ - def id(_struct, _conn), do: "1" -end