Skip to content

Commit

Permalink
Better handling of UUID setup
Browse files Browse the repository at this point in the history
  • Loading branch information
danschultzer committed Mar 26, 2018
1 parent d3cef0b commit ca144ec
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 60 deletions.
32 changes: 12 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,42 +277,34 @@ You'll need to create the migration file with the argument `--uuid resource_owne
mix ex_oauth2_provider.install --uuid resource_owners
```

### 2. If all structs should use `:uuid`

If you don't have auto-incrementing integers as primary keys in your database you can set up `ExOauth2Provider` to handle all primary keys as `:uuid` by doing the following.

You should have a schema macro similar to this (the `@primary_key` and `@foreign_key_type` needs to be defined):
And set the config to use `:binary_id` for `belongs_to` fields:

```elixir
defmodule MyApp.Schema do
@moduledoc false
defmacro __using__(_) do
quote do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
end
end
end
config :ex_oauth2_provider, ExOauth2Provider,
resource_owner: {Dummy.User, :binary_id}
```

Update the `:ex_oauth2_provider` config in `config/config.exs` to use the schema macro:
### 2. If all structs should use `:uuid`

If you don't have auto-incrementing integers as primary keys in your database you can set up `ExOauth2Provider` to handle all primary keys as `:uuid` by doing the following.

Update the `:ex_oauth2_provider` config in `config/config.exs` to use the the [UUID schema](lib/ex_oauth2_provider/schemas/uuid.ex) macro:

```elixir
config :ex_oauth2_provider, ExOauth2Provider,
# ...
app_schema: MyApp.Schema
resource_owner: {Dummy.User, :binary_id},
app_schema: ExOauth2Provider.Schema.UUID
```

And generate a migration file that uses `:uuid` type for all tables:
And generate a migration file that uses `:uuid` for all tables:

```bash
mix ex_oauth2_provider.install --uuid all
```

### 3. If you need something different than `:uuid`

It's also possible to use a completely different setup by adding a custom schema macro like in the section above. You'll have to update the migration file accordingly.
It's also possible to use a completely different setup by adding a custom schema macro, however you'll need to ensure that the schema file is compiled before this library and that you've updated the migration file accordingly.

## Acknowledgement

Expand Down
6 changes: 5 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ config :ex_oauth2_provider, ExOauth2Provider,
revoke_refresh_token_on_use: true,
grant_flows: ~w(authorization_code client_credentials)

if System.get_env("UUID") do
config :ex_oauth2_provider, ExOauth2Provider, resource_owner: {Dummy.User, :binary_id}
end

if System.get_env("UUID") == "all" do
config :ex_oauth2_provider, ExOauth2Provider, app_schema: Dummy.UUIDSchema
config :ex_oauth2_provider, ExOauth2Provider, app_schema: ExOauth2Provider.Schema.UUID
end

config :ex_oauth2_provider, ecto_repos: [ExOauth2Provider.Test.Repo]
Expand Down
23 changes: 17 additions & 6 deletions lib/ex_oauth2_provider/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ defmodule ExOauth2Provider.Config do
end

@doc false
@spec resource_owner_struct() :: atom
def resource_owner_struct do
Keyword.get(config(), :resource_owner)
@spec resource_owner_struct(atom) :: atom
def resource_owner_struct(type) do
config()
|> Keyword.get(:resource_owner)
|> parse_owner_struct(type)
end

@doc false
Expand All @@ -18,9 +20,13 @@ defmodule ExOauth2Provider.Config do
end

@doc false
@spec application_owner_struct() :: atom
def application_owner_struct do
Keyword.get(config(), :application_owner, resource_owner_struct())
@spec application_owner_struct(atom) :: atom
def application_owner_struct(type) do
resource_owner = Keyword.get(config(), :resource_owner)

config()
|> Keyword.get(:application_owner, resource_owner)
|> parse_owner_struct(type)
end

# Define default access token scopes for your provider
Expand Down Expand Up @@ -138,4 +144,9 @@ defmodule ExOauth2Provider.Config do
defp grant_type_can_be_used?(grant_flows, grant_type) do
Enum.member?(grant_flows, grant_type)
end

defp parse_owner_struct({_module, foreign_key_type}, :foreign_key_type), do: foreign_key_type
defp parse_owner_struct({module, _foreign_key_type}, :module), do: module
defp parse_owner_struct(module, :module), do: module
defp parse_owner_struct(_module, :foreign_key_type), do: :id
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ defmodule ExOauth2Provider.OauthAccessGrants.OauthAccessGrant do

use ExOauth2Provider.Schema
alias ExOauth2Provider.OauthApplications.OauthApplication
alias ExOauth2Provider.{Config, Utils}

@resource_owner_struct Config.resource_owner_struct()
@resource_owner_belongs_to_opts Utils.schema_belongs_to_opts(@resource_owner_struct)
alias ExOauth2Provider.Config

schema "oauth_access_grants" do
belongs_to :resource_owner, @resource_owner_struct, @resource_owner_belongs_to_opts
belongs_to :resource_owner, Config.resource_owner_struct(:module), type: Config.resource_owner_struct(:foreign_key_type)
belongs_to :application, OauthApplication

field :token, :string, null: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ defmodule ExOauth2Provider.OauthAccessTokens.OauthAccessToken do

use ExOauth2Provider.Schema
alias ExOauth2Provider.OauthApplications.OauthApplication
alias ExOauth2Provider.{Config, Utils}

@resource_owner_struct Config.resource_owner_struct()
@resource_owner_belongs_to_opts Utils.schema_belongs_to_opts(@resource_owner_struct)
alias ExOauth2Provider.Config

schema "oauth_access_tokens" do
belongs_to :resource_owner, Config.resource_owner_struct(:module), type: Config.resource_owner_struct(:foreign_key_type)
belongs_to :application, OauthApplication, on_replace: :nilify
belongs_to :resource_owner, @resource_owner_struct, @resource_owner_belongs_to_opts

field :token, :string, null: false
field :refresh_token, :string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ defmodule ExOauth2Provider.OauthApplications.OauthApplication do

use ExOauth2Provider.Schema
require Logger
alias ExOauth2Provider.{Config, Utils}
alias ExOauth2Provider.Config

# For Phoenix integrations
if Code.ensure_loaded?(Phoenix.Param) do
@derive {Phoenix.Param, key: :uid}
end

@owner_struct Config.application_owner_struct()
@owner_belongs_to_opts Utils.schema_belongs_to_opts(@owner_struct)
if is_nil(@owner_struct), do: Logger.error("You need to set a resource_owner or application_owner in your config and recompile ex_oauth2_provider!")
if is_nil(Config.application_owner_struct(:module)), do: Logger.error("You need to set a resource_owner or application_owner in your config and recompile ex_oauth2_provider!")

schema "oauth_applications" do
belongs_to :owner, @owner_struct, @owner_belongs_to_opts
belongs_to :owner, Config.application_owner_struct(:module), type: Config.application_owner_struct(:foreign_key_type)

field :name, :string, null: false
field :uid, :string, null: false
Expand Down
13 changes: 13 additions & 0 deletions lib/ex_oauth2_provider/schemas/uuid.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule ExOauth2Provider.Schema.UUID do
@moduledoc """
This module will permit autogenerated UUID.
"""

defmacro __using__(_) do
quote do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
end
end
end
4 changes: 0 additions & 4 deletions lib/ex_oauth2_provider/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,4 @@ defmodule ExOauth2Provider.Utils do
def schema_association(module, association) do
module.__schema__(:association, association)
end

@spec schema_belongs_to_opts(Ecto.Schema | nil) :: Keyword.t
def schema_belongs_to_opts(nil), do: []
def schema_belongs_to_opts(module), do: [type: module.__schema__(:type, :id)]
end
2 changes: 1 addition & 1 deletion test/support/dummy/models/user.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Dummy.User do
@moduledoc false

use Dummy.UUIDSchema
use Dummy.Schema
import Ecto.Changeset

schema "users" do
Expand Down
14 changes: 14 additions & 0 deletions test/support/dummy/schema.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Dummy.Schema do
@moduledoc """
This module will permit dynamic App.Schema load.
"""
defmacro __using__(_) do
schema = if is_nil(System.get_env("UUID")),
do: Ecto.Schema,
else: ExOauth2Provider.Schema.UUID

quote do
use unquote(schema)
end
end
end
12 changes: 0 additions & 12 deletions test/support/dummy/uuid_schema.ex

This file was deleted.

2 changes: 1 addition & 1 deletion test/support/fixture.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule ExOauth2Provider.Test.Fixture do
alias ExOauth2Provider.OauthAccessGrants
alias ExOauth2Provider.Test.Repo

@resource_owner ExOauth2Provider.Config.resource_owner_struct()
@resource_owner ExOauth2Provider.Config.resource_owner_struct(:module)

def fixture(:user, attrs \\ %{}) do
{:ok, user} = %@resource_owner{}
Expand Down

0 comments on commit ca144ec

Please sign in to comment.