Class: Seams::Generators::Auth::AddOauthProviderGenerator

Inherits:
FollowUpGenerator
  • Object
show all
Defined in:
lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb

Overview

Adds a new OAuth provider adapter to an already-generated Auth engine. The first showcase follow-up generator built on top of the Wave 10 Phase 1 insertion-point machinery.

Run with:

bin/rails generate seams:auth:add_oauth_provider linkedin
bin/rails generate seams:auth:add_oauth_provider apple
bin/rails generate seams:auth:add_oauth_provider microsoft

What it does:

1. Creates engines/auth/lib/auth/oauth/<name>.rb (subclasses
   Auth::OAuth::Abstract, with TODOs the host fills in).
2. Splices a configuration entry into
   engines/auth/lib/auth/configuration.rb at the
   `auth.configuration.oauth_providers` marker.
3. Creates engines/auth/spec/lib/auth/oauth/<name>_spec.rb
   covering the abstract contract.

The existing ‘scope “/oauth/:provider”` route in engines/auth/config/routes.rb already handles every configured provider via the `:provider` param — the generator does NOT splice into auth.routes.after_oauth or any other route marker. Likewise, the `_oauth_buttons.html.erb` partial iterates `Auth.configuration.oauth_providers.each_key`, so the new entry auto-renders without a partial edit.

Idempotent on rerun: the underlying Splicer detects the splice has already happened and skips. The adapter file itself is written via ‘template`, which Thor’s –skip flag (default) leaves alone if it already exists.

Constant Summary collapse

NAME_PATTERN =

Provider names share the engine-name regex: lowercase letters, digits, underscores, starting with a letter. Hyphens, mixed case, and dots are normalised to underscores by ‘snake_name`.

/\A[a-z][a-z0-9_]*\z/
CONFIGURATION_FILE =
"lib/auth/configuration.rb"
CONFIGURATION_MARKER =
"auth.configuration.oauth_providers"

Instance Method Summary collapse

Methods inherited from FollowUpGenerator

engine_name

Instance Method Details

#assert_engine_presentObject



76
77
78
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 76

def assert_engine_present
  assert_marker_exists!(file: CONFIGURATION_FILE, marker: CONFIGURATION_MARKER)
end

#create_adapterObject



80
81
82
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 80

def create_adapter
  template "adapter.rb.tt", engine_path("lib/auth/oauth/#{snake_name}.rb")
end

#create_adapter_specObject



92
93
94
95
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 92

def create_adapter_spec
  template "adapter_spec.rb.tt",
           engine_path("spec/lib/auth/oauth/#{snake_name}_spec.rb")
end

#normalise_nameObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 58

def normalise_name
  @snake_name = name.to_s.strip.downcase
                    .gsub(/[^a-z0-9]+/, "_").squeeze("_")
                    .gsub(/^_|_$/, "")

  if @snake_name.empty?
    raise Seams::GeneratorError,
          "Provider name #{name.inspect} normalises to an empty string. " \
          "Pass a name like `linkedin`, `apple`, or `microsoft`."
  end

  return if NAME_PATTERN.match?(@snake_name)

  raise Seams::GeneratorError,
        "Provider name #{name.inspect} must be lowercase letters, digits, " \
        "and underscores, starting with a letter."
end

#report_summaryObject

rubocop:disable Metrics/AbcSize



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 98

def report_summary
  say ""
  say "  Auth OAuth provider `#{snake_name}` added.", :green
  say ""
  say "  Files:", :yellow
  say "    engines/auth/lib/auth/oauth/#{snake_name}.rb"
  say "    engines/auth/spec/lib/auth/oauth/#{snake_name}_spec.rb"
  say "  Spliced:", :yellow
  say "    engines/auth/lib/auth/configuration.rb @ #{CONFIGURATION_MARKER}"
  say ""
  say "  Routes: the existing `scope \"/oauth/:provider\"` block matches", :blue
  say "          every configured provider — no route splice needed."
  say "  View:   the engine's _oauth_buttons.html.erb partial iterates", :blue
  say "          Auth.configuration.oauth_providers — no partial edit needed."
  say ""
  say "  Next steps:", :yellow
  say "    1. Set #{upper_name}_OAUTH_CLIENT_ID and #{upper_name}_OAUTH_CLIENT_SECRET in your environment."
  say "    2. Replace the TODO placeholders in lib/auth/oauth/#{snake_name}.rb with"
  say "       the provider's real OAuth endpoints + userinfo mapping."
  say "    3. Run the spec: bin/rails seams:test[auth] (or rspec the new file)."
  say "    4. Test the OAuth flow against the provider's sandbox."
  say ""
  say "  Want to customise the adapter beyond the TODOs (override behaviour, change the", :blue
  say "  spec shape, etc.)? Eject it so subsequent regenerations of auth leave it alone:"
  say "    bin/seams resolve --eject auth/lib/auth/oauth/#{snake_name}.rb"
  say ""
end

#splice_configuration_entryObject



84
85
86
87
88
89
90
# File 'lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb', line 84

def splice_configuration_entry
  splice(
    file: CONFIGURATION_FILE,
    marker: CONFIGURATION_MARKER,
    content: configuration_entry
  )
end