plutonium 0.41.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/app/assets/plutonium.css +2 -2
- data/app/assets/plutonium.js +46 -1
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +32 -32
- data/app/assets/plutonium.min.js.map +4 -4
- data/docs/guides/user-invites.md +1 -1
- data/docs/reference/generators/index.md +43 -0
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/invites/templates/app/interactions/invite_user_interaction.rb.tt +2 -0
- data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt +3 -1
- data/lib/generators/pu/invites/templates/invitable/invite_user_interaction.rb.tt +3 -1
- data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +1 -1
- data/lib/generators/pu/rodauth/account_generator.rb +20 -5
- data/lib/generators/pu/rodauth/admin_generator.rb +1 -1
- data/lib/generators/pu/rodauth/concerns/configuration.rb +1 -0
- data/lib/generators/pu/rodauth/concerns/gem_helpers.rb +19 -0
- data/lib/generators/pu/rodauth/install_generator.rb +7 -3
- data/lib/generators/pu/rodauth/migration/active_record/base.erb +4 -4
- data/lib/generators/pu/rodauth/migration_generator.rb +7 -0
- data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +1 -1
- data/lib/generators/pu/saas/USAGE +10 -1
- data/lib/generators/pu/saas/api_client/USAGE +32 -0
- data/lib/generators/pu/saas/api_client/templates/app/interactions/create_interaction.rb.tt +80 -0
- data/lib/generators/pu/saas/api_client/templates/app/interactions/disable_interaction.rb.tt +15 -0
- data/lib/generators/pu/saas/api_client/templates/lib/tasks/api_client.rake.tt +48 -0
- data/lib/generators/pu/saas/api_client_generator.rb +254 -0
- data/lib/generators/pu/saas/entity_generator.rb +5 -3
- data/lib/generators/pu/saas/membership_generator.rb +21 -9
- data/lib/generators/pu/saas/setup_generator.rb +23 -0
- data/lib/plutonium/api_client/concerns/create_api_client.rb +256 -0
- data/lib/plutonium/api_client/concerns/disable_api_client.rb +64 -0
- data/lib/plutonium/api_client.rb +21 -0
- data/lib/plutonium/interaction/concerns/scoping.rb +68 -0
- data/lib/plutonium/interaction/response/render.rb +16 -1
- data/lib/plutonium/invites/concerns/invite_user.rb +1 -1
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- data/src/js/controllers/clipboard_controller.js +37 -0
- data/src/js/controllers/register_controllers.js +2 -0
- data/src/js/controllers/remote_modal_controller.js +18 -4
- metadata +13 -2
data/docs/guides/user-invites.md
CHANGED
|
@@ -359,7 +359,7 @@ In your admin portal:
|
|
|
359
359
|
```ruby
|
|
360
360
|
# Invites are scoped to the current entity
|
|
361
361
|
# Admins see all pending invites for their organization
|
|
362
|
-
Invites::UserInvite.pending.where(entity:
|
|
362
|
+
Invites::UserInvite.pending.where(entity: current_scoped_entity)
|
|
363
363
|
```
|
|
364
364
|
|
|
365
365
|
## Security Considerations
|
|
@@ -410,6 +410,7 @@ Generate a complete multi-tenant SaaS setup with user, entity, and membership.
|
|
|
410
410
|
rails generate pu:saas:setup --user Customer --entity Organization
|
|
411
411
|
rails generate pu:saas:setup --user Customer --entity Organization --roles=member,admin,owner
|
|
412
412
|
rails generate pu:saas:setup --user Customer --entity Organization --no-allow-signup
|
|
413
|
+
rails generate pu:saas:setup --user Customer --entity Organization --api_client ApiClient
|
|
413
414
|
```
|
|
414
415
|
|
|
415
416
|
#### Options
|
|
@@ -425,12 +426,15 @@ rails generate pu:saas:setup --user Customer --entity Organization --no-allow-si
|
|
|
425
426
|
| `--user-attributes` | Additional user model attributes |
|
|
426
427
|
| `--entity-attributes` | Additional entity model attributes |
|
|
427
428
|
| `--membership-attributes` | Additional membership model attributes |
|
|
429
|
+
| `--api_client NAME` | Generate an API client model for M2M auth |
|
|
430
|
+
| `--api_client_roles` | Roles for API client (default: read_only,write,admin) |
|
|
428
431
|
|
|
429
432
|
Creates:
|
|
430
433
|
- User account model with Rodauth authentication
|
|
431
434
|
- Entity model with unique name
|
|
432
435
|
- Membership join model with role enum
|
|
433
436
|
- Has-many-through associations with `dependent: :destroy`
|
|
437
|
+
- (Optional) API client with HTTP Basic Auth, scoped to entity
|
|
434
438
|
|
|
435
439
|
### pu:saas:user
|
|
436
440
|
|
|
@@ -460,6 +464,45 @@ rails generate pu:saas:membership --user Customer --entity Organization
|
|
|
460
464
|
rails generate pu:saas:membership --user Customer --entity Organization --roles=member,admin,owner
|
|
461
465
|
```
|
|
462
466
|
|
|
467
|
+
### pu:saas:api_client
|
|
468
|
+
|
|
469
|
+
Generate an API client account for machine-to-machine authentication.
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
rails generate pu:saas:api_client ApiClient
|
|
473
|
+
rails generate pu:saas:api_client ApiClient --entity=Organization
|
|
474
|
+
rails generate pu:saas:api_client ApiClient --entity=Organization --roles=read_only,write,admin
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
#### Options
|
|
478
|
+
|
|
479
|
+
| Option | Description |
|
|
480
|
+
|--------|-------------|
|
|
481
|
+
| `--entity NAME` | Entity model to scope API clients to |
|
|
482
|
+
| `--roles` | Available roles (default: read_only,write,admin) |
|
|
483
|
+
| `--extra_attributes` | Additional model attributes |
|
|
484
|
+
| `--dest` | Destination package |
|
|
485
|
+
|
|
486
|
+
Creates:
|
|
487
|
+
- Rodauth account with HTTP Basic Auth (login + auto-generated password)
|
|
488
|
+
- Create and Disable interactions
|
|
489
|
+
- Rake task for CLI creation (`rake api_clients:create`)
|
|
490
|
+
- (If entity) Membership model with roles
|
|
491
|
+
|
|
492
|
+
#### Usage
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
# Create via rake task
|
|
496
|
+
rake api_clients:create LOGIN=my-service
|
|
497
|
+
|
|
498
|
+
# With entity scoping
|
|
499
|
+
rake api_clients:create LOGIN=my-service ORGANIZATION=acme ROLE=write
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
::: tip Credentials
|
|
503
|
+
Credentials are displayed once on creation and cannot be retrieved later. The password is auto-generated using `SecureRandom.base64(32)`.
|
|
504
|
+
:::
|
|
505
|
+
|
|
463
506
|
## Core Generators
|
|
464
507
|
|
|
465
508
|
### pu:core:install
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
class <%= entity_model %>::InviteUserInteraction < Plutonium::Resource::Interaction
|
|
4
4
|
include Plutonium::Invites::Concerns::InviteUser
|
|
5
5
|
|
|
6
|
+
presents label: "Invite <%= user_model.underscore.humanize.titleize %>", icon: Phlex::TablerIcons::Mail
|
|
7
|
+
|
|
6
8
|
attribute :role
|
|
7
9
|
input :role, as: :select, choices: Invites::UserInvite.roles.keys
|
|
8
10
|
<% if membership_model != "EntityUser" || user_model != "User" -%>
|
data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
class <%= user_model %>::InviteUserInteraction < Plutonium::Resource::Interaction
|
|
4
4
|
include Plutonium::Invites::Concerns::InviteUser
|
|
5
5
|
|
|
6
|
+
presents label: "Invite <%= user_model.underscore.humanize.titleize %>", icon: Phlex::TablerIcons::Mail
|
|
7
|
+
|
|
6
8
|
attribute :role
|
|
7
9
|
input :role, as: :select, choices: Invites::UserInvite.roles.keys
|
|
8
10
|
|
|
9
11
|
private
|
|
10
12
|
|
|
11
13
|
def entity
|
|
12
|
-
|
|
14
|
+
current_scoped_entity
|
|
13
15
|
end
|
|
14
16
|
<% if membership_model != "EntityUser" -%>
|
|
15
17
|
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
class <%= model_class %>::InviteUserInteraction < Plutonium::Resource::Interaction
|
|
4
4
|
include Plutonium::Invites::Concerns::InviteUser
|
|
5
5
|
|
|
6
|
+
presents label: "Invite <%= user_model.underscore.humanize.titleize %>", icon: Phlex::TablerIcons::Mail
|
|
7
|
+
|
|
6
8
|
input :email
|
|
7
9
|
|
|
8
10
|
private
|
|
9
11
|
|
|
10
12
|
def entity
|
|
11
|
-
|
|
13
|
+
current_scoped_entity
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def invitable
|
|
@@ -22,7 +22,7 @@ module PlutoniumGenerators
|
|
|
22
22
|
|
|
23
23
|
def available_packages
|
|
24
24
|
@available_packages ||= begin
|
|
25
|
-
packages = Dir["packages
|
|
25
|
+
packages = Dir[Rails.root.join("packages", "*")].map { |dir| File.basename(dir) }
|
|
26
26
|
packages - reserved_packages
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -6,12 +6,14 @@ require "securerandom"
|
|
|
6
6
|
require "#{__dir__}/concerns/configuration"
|
|
7
7
|
require "#{__dir__}/concerns/account_selector"
|
|
8
8
|
require "#{__dir__}/concerns/feature_selector"
|
|
9
|
+
require "#{__dir__}/concerns/gem_helpers"
|
|
9
10
|
|
|
10
11
|
module Pu
|
|
11
12
|
module Rodauth
|
|
12
13
|
class AccountGenerator < ::Rails::Generators::Base
|
|
13
14
|
include Concerns::AccountSelector
|
|
14
15
|
include Concerns::FeatureSelector
|
|
16
|
+
include Concerns::GemHelpers
|
|
15
17
|
|
|
16
18
|
source_root "#{__dir__}/templates"
|
|
17
19
|
|
|
@@ -21,12 +23,20 @@ module Pu
|
|
|
21
23
|
class_option :extra_attributes, type: :array, default: [],
|
|
22
24
|
desc: "Additional attributes to add to the account model (e.g., role:integer)"
|
|
23
25
|
|
|
26
|
+
class_option :login_column, type: :string, default: "email",
|
|
27
|
+
desc: "Name of the login column (default: email)"
|
|
28
|
+
|
|
24
29
|
def install_dependencies
|
|
30
|
+
gems = []
|
|
31
|
+
gems << "jwt" if jwt? || jwt_refresh?
|
|
32
|
+
gems << "rotp" if otp?
|
|
33
|
+
gems << "rqrcode" if otp?
|
|
34
|
+
gems << "webauthn" if webauthn? || webauthn_autofill?
|
|
35
|
+
gems = gems.reject { |g| gem_in_bundle?(g) }
|
|
36
|
+
return if gems.empty?
|
|
37
|
+
|
|
25
38
|
Bundler.with_unbundled_env do
|
|
26
|
-
run "bundle add
|
|
27
|
-
run "bundle add rotp" if otp?
|
|
28
|
-
run "bundle add rqrcode" if otp?
|
|
29
|
-
run "bundle add webauthn" if webauthn? || webauthn_autofill?
|
|
39
|
+
gems.each { |gem| run "bundle add #{gem}" }
|
|
30
40
|
end
|
|
31
41
|
end
|
|
32
42
|
|
|
@@ -91,6 +101,7 @@ module Pu
|
|
|
91
101
|
invoke "pu:rodauth:migration", [table], features: selected_migration_features,
|
|
92
102
|
name: kitchen_sink? ? "rodauth_kitchen_sink" : nil,
|
|
93
103
|
migration_name: options[:migration_name],
|
|
104
|
+
login_column: login_column,
|
|
94
105
|
force: options[:force],
|
|
95
106
|
skip: options[:skip]
|
|
96
107
|
|
|
@@ -113,7 +124,7 @@ module Pu
|
|
|
113
124
|
return unless base?
|
|
114
125
|
|
|
115
126
|
template "app/models/account.rb", "app/models/#{account_path}.rb"
|
|
116
|
-
scaffold_attrs = ["
|
|
127
|
+
scaffold_attrs = ["#{login_column}:string", "status:integer"] + Array(options[:extra_attributes])
|
|
117
128
|
invoke "pu:res:scaffold", [table, *scaffold_attrs], dest: "main_app",
|
|
118
129
|
model: false,
|
|
119
130
|
force: true,
|
|
@@ -133,6 +144,10 @@ module Pu
|
|
|
133
144
|
def only_json?
|
|
134
145
|
::Rails.application.config.api_only || !::Rails.application.config.session_store || options[:api_only]
|
|
135
146
|
end
|
|
147
|
+
|
|
148
|
+
def login_column
|
|
149
|
+
options[:login_column] || "email"
|
|
150
|
+
end
|
|
136
151
|
end
|
|
137
152
|
end
|
|
138
153
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pu
|
|
4
|
+
module Rodauth
|
|
5
|
+
module Concerns
|
|
6
|
+
module GemHelpers
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def gem_in_bundle?(name)
|
|
10
|
+
in_root do
|
|
11
|
+
return true if File.exist?("Gemfile") && File.read("Gemfile").match?(/gem ['"]#{name}['"]/)
|
|
12
|
+
return true if File.exist?("Gemfile.lock") && File.read("Gemfile.lock").include?(" #{name} ")
|
|
13
|
+
end
|
|
14
|
+
false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -2,20 +2,24 @@ require "rails/generators/base"
|
|
|
2
2
|
require "rails/generators/active_record/migration"
|
|
3
3
|
require "securerandom"
|
|
4
4
|
|
|
5
|
+
require "#{__dir__}/concerns/gem_helpers"
|
|
6
|
+
|
|
5
7
|
module Pu
|
|
6
8
|
module Rodauth
|
|
7
9
|
class InstallGenerator < ::Rails::Generators::Base
|
|
8
10
|
include ::ActiveRecord::Generators::Migration
|
|
11
|
+
include Concerns::GemHelpers
|
|
9
12
|
|
|
10
13
|
source_root "#{__dir__}/templates"
|
|
11
14
|
|
|
12
15
|
desc "Install rodauth-rails"
|
|
13
16
|
|
|
14
17
|
def add_rodauth
|
|
18
|
+
gems = %w[bcrypt sequel-activerecord_connection tilt rodauth-rails].reject { |g| gem_in_bundle?(g) }
|
|
19
|
+
return if gems.empty?
|
|
20
|
+
|
|
15
21
|
Bundler.with_unbundled_env do
|
|
16
|
-
|
|
17
|
-
run "bundle add #{gem}"
|
|
18
|
-
end
|
|
22
|
+
gems.each { |gem| run "bundle add #{gem}" }
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
|
|
@@ -2,15 +2,15 @@ create_table :<%= table_prefix.pluralize %><%= primary_key_type %> do |t|
|
|
|
2
2
|
t.integer :status, null: false, default: 1
|
|
3
3
|
<% case activerecord_adapter -%>
|
|
4
4
|
<% when "postgresql" -%>
|
|
5
|
-
t.citext
|
|
5
|
+
t.citext :<%= login_column %>, null: false
|
|
6
6
|
<% else -%>
|
|
7
|
-
t.string
|
|
7
|
+
t.string :<%= login_column %>, null: false
|
|
8
8
|
<% end -%>
|
|
9
9
|
<% case activerecord_adapter -%>
|
|
10
10
|
<% when "postgresql", "sqlite3" -%>
|
|
11
|
-
t.index
|
|
11
|
+
t.index :<%= login_column %>, unique: true, where: "status IN (1, 2)"
|
|
12
12
|
<% else -%>
|
|
13
|
-
t.index
|
|
13
|
+
t.index :<%= login_column %>, unique: true
|
|
14
14
|
<% end -%>
|
|
15
15
|
<% unless separate_passwords? -%>
|
|
16
16
|
t.string :password_hash
|
|
@@ -27,6 +27,9 @@ module Pu
|
|
|
27
27
|
class_option :features, required: true, type: :array,
|
|
28
28
|
desc: "Rodauth features to create tables for (otp, sms_codes, single_session, account_expiration etc.)"
|
|
29
29
|
|
|
30
|
+
class_option :login_column, type: :string, default: "email",
|
|
31
|
+
desc: "Name of the login column (default: email)"
|
|
32
|
+
|
|
30
33
|
def validate_selected_features
|
|
31
34
|
if selected_features.empty?
|
|
32
35
|
say "No migration features specified!", :yellow
|
|
@@ -119,6 +122,10 @@ module Pu
|
|
|
119
122
|
selected_features.include? :separate_passwords
|
|
120
123
|
end
|
|
121
124
|
|
|
125
|
+
def login_column
|
|
126
|
+
options[:login_column] || "email"
|
|
127
|
+
end
|
|
128
|
+
|
|
122
129
|
def migration_chunk(feature)
|
|
123
130
|
"#{MIGRATION_DIR}/#{feature}.erb"
|
|
124
131
|
end
|
|
@@ -2,10 +2,11 @@ Description:
|
|
|
2
2
|
SaaS generators for multi-tenant applications with user accounts, entities, and memberships.
|
|
3
3
|
|
|
4
4
|
Generators:
|
|
5
|
-
pu:saas:setup Complete SaaS setup (user + entity + membership)
|
|
5
|
+
pu:saas:setup Complete SaaS setup (user + entity + membership + optional api_client)
|
|
6
6
|
pu:saas:user SaaS user account with Rodauth
|
|
7
7
|
pu:saas:entity Entity/organization model
|
|
8
8
|
pu:saas:membership Membership join table linking users to entities
|
|
9
|
+
pu:saas:api_client API client account for machine-to-machine auth
|
|
9
10
|
|
|
10
11
|
Example:
|
|
11
12
|
rails g pu:saas:setup --user Customer --entity Organization
|
|
@@ -15,8 +16,16 @@ Example:
|
|
|
15
16
|
- Organization entity model with unique name
|
|
16
17
|
- OrganizationCustomer membership model with role enum
|
|
17
18
|
|
|
19
|
+
With API client:
|
|
20
|
+
rails g pu:saas:setup --user Customer --entity Organization --api_client ApiClient
|
|
21
|
+
|
|
22
|
+
This also creates:
|
|
23
|
+
- ApiClient account with HTTP Basic Auth
|
|
24
|
+
- OrganizationApiClient membership model with roles
|
|
25
|
+
|
|
18
26
|
See individual generator help for more options:
|
|
19
27
|
rails g pu:saas:setup --help
|
|
20
28
|
rails g pu:saas:user --help
|
|
21
29
|
rails g pu:saas:entity --help
|
|
22
30
|
rails g pu:saas:membership --help
|
|
31
|
+
rails g pu:saas:api_client --help
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generate an API client account for machine-to-machine authentication.
|
|
3
|
+
|
|
4
|
+
API clients use HTTP Basic Auth with application name (login) and
|
|
5
|
+
auto-generated password. Credentials are displayed once on creation
|
|
6
|
+
and cannot be reset - only disabled or deleted.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
# Basic API client (platform-level)
|
|
10
|
+
rails generate pu:saas:api_client ApiClient
|
|
11
|
+
|
|
12
|
+
# API client scoped to an organization with roles
|
|
13
|
+
rails generate pu:saas:api_client ApiClient --entity=Organization
|
|
14
|
+
|
|
15
|
+
# Custom roles
|
|
16
|
+
rails generate pu:saas:api_client ApiClient --entity=Organization --roles=read_only,write,admin
|
|
17
|
+
|
|
18
|
+
# With extra attributes
|
|
19
|
+
rails generate pu:saas:api_client ApiClient --extra_attributes=description:string,rate_limit:integer
|
|
20
|
+
|
|
21
|
+
This will create:
|
|
22
|
+
- Rodauth account with HTTP Basic Auth
|
|
23
|
+
- Create and Disable interactions
|
|
24
|
+
- Rake task for CLI creation
|
|
25
|
+
- If --entity: membership model with roles
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
# Create via rake task
|
|
29
|
+
rake api_clients:create LOGIN=my-service
|
|
30
|
+
|
|
31
|
+
# Or with entity
|
|
32
|
+
rake api_clients:create LOGIN=my-service ORGANIZATION=acme ROLE=write
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= name.classify %>::CreateInteraction < Plutonium::Resource::Interaction
|
|
4
|
+
include Plutonium::ApiClient::Concerns::CreateApiClient
|
|
5
|
+
|
|
6
|
+
<% if entity? -%>
|
|
7
|
+
attribute :<%= normalized_entity_name %>_id, :integer
|
|
8
|
+
attribute :role, :string, default: "<%= default_role %>"
|
|
9
|
+
|
|
10
|
+
validates :<%= normalized_entity_name %>_id, presence: true
|
|
11
|
+
validates :role, presence: true, inclusion: {in: <%= membership_model_name.classify %>.roles.keys}
|
|
12
|
+
|
|
13
|
+
# Only show entity picker if not in a scoped context
|
|
14
|
+
input :<%= normalized_entity_name %>_id, if: -> { scoped_entity.nil? } do |f|
|
|
15
|
+
choices = <%= normalized_entity_name.classify %>.pluck(:name, :id)
|
|
16
|
+
f.select_tag choices: choices
|
|
17
|
+
end
|
|
18
|
+
input :role, as: :select, choices: <%= membership_model_name.classify %>.roles.keys
|
|
19
|
+
|
|
20
|
+
def initialize(**)
|
|
21
|
+
super
|
|
22
|
+
self.<%= normalized_entity_name %>_id ||= scoped_entity&.id
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
<% end -%>
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def rodauth_name
|
|
29
|
+
:<%= normalized_name %>
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def api_client_class
|
|
33
|
+
<%= name.classify %>
|
|
34
|
+
end
|
|
35
|
+
<% if entity? -%>
|
|
36
|
+
|
|
37
|
+
def entity_class
|
|
38
|
+
<%= normalized_entity_name.classify %>
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def membership_class
|
|
42
|
+
<%= membership_model_name.classify %>
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def scoped_entity_id
|
|
46
|
+
<%= normalized_entity_name %>_id
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Custom credentials page with proper resource URL
|
|
50
|
+
class CredentialsPage < Plutonium::ApiClient::Concerns::CreateApiClient::CredentialsPage
|
|
51
|
+
def success_title
|
|
52
|
+
"<%= display_name.titleize %> Created Successfully"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def done_url
|
|
56
|
+
helpers.resource_url_for(<%= name.classify %>, parent: @parent)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def credentials_page_class
|
|
61
|
+
CredentialsPage
|
|
62
|
+
end
|
|
63
|
+
<% else -%>
|
|
64
|
+
|
|
65
|
+
# Custom credentials page with proper resource URL
|
|
66
|
+
class CredentialsPage < Plutonium::ApiClient::Concerns::CreateApiClient::CredentialsPage
|
|
67
|
+
def success_title
|
|
68
|
+
"<%= display_name.titleize %> Created Successfully"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def done_url
|
|
72
|
+
helpers.resource_url_for(<%= name.classify %>)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def credentials_page_class
|
|
77
|
+
CredentialsPage
|
|
78
|
+
end
|
|
79
|
+
<% end -%>
|
|
80
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= name.classify %>::DisableInteraction < Plutonium::Resource::Interaction
|
|
4
|
+
include Plutonium::ApiClient::Concerns::DisableApiClient
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def rodauth_name
|
|
9
|
+
:<%= normalized_name %>
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def success_message(login)
|
|
13
|
+
"<%= display_name.titleize %> '#{login}' has been disabled"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :<%= normalized_name.pluralize %> do
|
|
4
|
+
desc "Create a new <%= display_name %>"
|
|
5
|
+
task create: :environment do
|
|
6
|
+
require "tty-prompt"
|
|
7
|
+
|
|
8
|
+
prompt = TTY::Prompt.new
|
|
9
|
+
|
|
10
|
+
login = ENV["LOGIN"] || prompt.ask("Application name:", required: true)
|
|
11
|
+
<% if entity? -%>
|
|
12
|
+
<%= normalized_entity_name %>_name = ENV["<%= normalized_entity_name.upcase %>"] || prompt.ask("<%= normalized_entity_name.titleize %> name:", required: true)
|
|
13
|
+
role = ENV["ROLE"] || prompt.select("Role:", %w[<%= roles.join(" ") %>])
|
|
14
|
+
|
|
15
|
+
<%= normalized_entity_name %> = <%= normalized_entity_name.classify %>.find_by!(name: <%= normalized_entity_name %>_name)
|
|
16
|
+
<% end -%>
|
|
17
|
+
|
|
18
|
+
password = SecureRandom.base64(32)
|
|
19
|
+
|
|
20
|
+
RodauthApp.rodauth(:<%= normalized_name %>).create_account(
|
|
21
|
+
login: login,
|
|
22
|
+
password: password
|
|
23
|
+
)
|
|
24
|
+
<% if entity? -%>
|
|
25
|
+
|
|
26
|
+
<%= normalized_name %> = <%= name.classify %>.find_by!(login: login)
|
|
27
|
+
|
|
28
|
+
<%= membership_model_name.classify %>.create!(
|
|
29
|
+
<%= normalized_entity_name %>: <%= normalized_entity_name %>,
|
|
30
|
+
<%= normalized_name %>: <%= normalized_name %>,
|
|
31
|
+
role: role
|
|
32
|
+
)
|
|
33
|
+
<% end -%>
|
|
34
|
+
|
|
35
|
+
puts
|
|
36
|
+
puts "=== <%= display_name.titleize %> Created ==="
|
|
37
|
+
puts
|
|
38
|
+
puts "Login: #{login}"
|
|
39
|
+
puts "Password: #{password}"
|
|
40
|
+
<% if entity? -%>
|
|
41
|
+
puts "<%= normalized_entity_name.titleize %>: #{<%= normalized_entity_name %>.name}"
|
|
42
|
+
puts "Role: #{role}"
|
|
43
|
+
<% end -%>
|
|
44
|
+
puts
|
|
45
|
+
puts "IMPORTANT: Save these credentials now. The password cannot be retrieved later."
|
|
46
|
+
puts
|
|
47
|
+
end
|
|
48
|
+
end
|