plutonium 0.39.1 → 0.40.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/.claude/skills/plutonium-connect-resource/SKILL.md +19 -1
- data/.claude/skills/plutonium-controller/SKILL.md +5 -9
- data/.claude/skills/plutonium-definition-query/SKILL.md +10 -2
- data/.claude/skills/plutonium-installation/SKILL.md +9 -7
- data/.claude/skills/plutonium-invites/SKILL.md +363 -0
- data/.claude/skills/plutonium-package/SKILL.md +2 -1
- data/.claude/skills/plutonium-portal/SKILL.md +30 -16
- data/.claude/skills/plutonium-rodauth/SKILL.md +111 -18
- data/CHANGELOG.md +48 -0
- data/app/assets/plutonium.css +1 -1
- data/config/initializers/sqlite_alias.rb +8 -8
- data/docs/.vitepress/config.ts +1 -0
- data/docs/getting-started/tutorial/07-author-portal.md +1 -0
- data/docs/getting-started/tutorial/08-customizing-ui.md +5 -2
- data/docs/guides/adding-resources.md +10 -0
- data/docs/guides/authentication.md +15 -8
- data/docs/guides/creating-packages.md +13 -8
- data/docs/guides/index.md +2 -0
- data/docs/guides/search-filtering.md +8 -3
- data/docs/guides/user-invites.md +497 -0
- data/docs/public/templates/base.rb +5 -1
- data/docs/public/templates/lite.rb +42 -0
- data/docs/public/templates/pluton8.rb +7 -2
- data/docs/reference/controller/index.md +12 -7
- data/docs/reference/definition/query.md +12 -3
- data/docs/reference/generators/index.md +70 -10
- data/docs/reference/portal/index.md +22 -11
- 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/gem/active_shrine/active_shrine_generator.rb +31 -0
- data/lib/generators/pu/gem/active_shrine/templates/config/initializers/shrine.rb.tt +58 -0
- data/lib/generators/pu/gem/annotated/templates/lib/tasks/auto_annotate_models.rake +6 -1
- data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -0
- data/lib/generators/pu/invites/USAGE +27 -0
- data/lib/generators/pu/invites/install_generator.rb +364 -0
- data/lib/generators/pu/invites/invitable/USAGE +31 -0
- data/lib/generators/pu/invites/invitable_generator.rb +143 -0
- data/lib/generators/pu/invites/templates/INSTRUCTIONS +22 -0
- data/lib/generators/pu/invites/templates/app/interactions/invite_user_interaction.rb.tt +24 -0
- data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt +26 -0
- data/lib/generators/pu/invites/templates/db/migrate/create_user_invites.rb.tt +47 -0
- data/lib/generators/pu/invites/templates/invitable/invitation.html.erb.tt +45 -0
- data/lib/generators/pu/invites/templates/invitable/invitation.text.erb.tt +15 -0
- data/lib/generators/pu/invites/templates/invitable/invite_user_interaction.rb.tt +33 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/user_invitations_controller.rb.tt +77 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/welcome_controller.rb.tt +68 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/definitions/invites/user_invite_definition.rb.tt +23 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/cancel_invite_interaction.rb.tt +7 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/resend_invite_interaction.rb.tt +7 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/mailers/invites/user_invite_mailer.rb.tt +34 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/models/invites/user_invite.rb.tt +41 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/policies/invites/user_invite_policy.rb.tt +33 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/error.html.erb.tt +24 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/landing.html.erb.tt +40 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/show.html.erb.tt +39 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/signup.html.erb.tt +49 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.html.erb.tt +45 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.text.erb.tt +15 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/welcome/pending_invitation.html.erb.tt +23 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/layouts/invites/invitation.html.erb.tt +33 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +23 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/configures_sqlite.rb +130 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb +72 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +4 -2
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +7 -1
- data/lib/generators/pu/lite/litestream/litestream_generator.rb +105 -0
- data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +88 -0
- data/lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt +14 -0
- data/lib/generators/pu/lite/setup/setup_generator.rb +54 -0
- data/lib/generators/pu/lite/solid_cable/solid_cable_generator.rb +65 -0
- data/lib/generators/pu/lite/solid_cache/solid_cache_generator.rb +66 -0
- data/lib/generators/pu/lite/solid_errors/solid_errors_generator.rb +61 -0
- data/lib/generators/pu/lite/solid_queue/solid_queue_generator.rb +107 -0
- data/lib/generators/pu/pkg/portal/USAGE +8 -2
- data/lib/generators/pu/pkg/portal/portal_generator.rb +11 -1
- data/lib/generators/pu/pkg/portal/templates/app/controllers/concerns/controller.rb.tt +2 -0
- data/lib/generators/pu/pkg/portal/templates/app/controllers/plutonium_controller.rb.tt +1 -0
- data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +7 -0
- data/lib/generators/pu/pkg/portal/templates/lib/engine.rb.tt +3 -0
- data/lib/generators/pu/res/conn/USAGE +5 -0
- data/lib/generators/pu/res/conn/conn_generator.rb +30 -4
- data/lib/generators/pu/res/scaffold/scaffold_generator.rb +6 -3
- data/lib/generators/pu/res/scaffold/templates/policy.rb.tt +6 -6
- data/lib/generators/pu/rodauth/account_generator.rb +36 -11
- data/lib/generators/pu/rodauth/admin_generator.rb +55 -0
- data/lib/generators/pu/rodauth/install_generator.rb +1 -8
- data/lib/generators/pu/rodauth/templates/app/interactions/invite_admin_interaction.rb.tt +25 -0
- data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +6 -2
- data/lib/generators/pu/saas/USAGE +22 -0
- data/lib/generators/pu/saas/entity/USAGE +19 -0
- data/lib/generators/pu/saas/entity_generator.rb +55 -0
- data/lib/generators/pu/saas/membership/USAGE +25 -0
- data/lib/generators/pu/saas/membership_generator.rb +165 -0
- data/lib/generators/pu/saas/setup/USAGE +27 -0
- data/lib/generators/pu/saas/setup_generator.rb +98 -0
- data/lib/generators/pu/saas/user/USAGE +21 -0
- data/lib/generators/pu/saas/user_generator.rb +66 -0
- data/lib/plutonium/core/controller.rb +9 -5
- data/lib/plutonium/definition/base.rb +3 -1
- data/lib/plutonium/definition/scoping.rb +20 -0
- data/lib/plutonium/invites/concerns/cancel_invite.rb +44 -0
- data/lib/plutonium/invites/concerns/invitable.rb +98 -0
- data/lib/plutonium/invites/concerns/invite_token.rb +186 -0
- data/lib/plutonium/invites/concerns/invite_user.rb +147 -0
- data/lib/plutonium/invites/concerns/resend_invite.rb +66 -0
- data/lib/plutonium/invites/controller.rb +226 -0
- data/lib/plutonium/invites/pending_invite_check.rb +76 -0
- data/lib/plutonium/invites.rb +6 -0
- data/lib/plutonium/resource/controllers/queryable.rb +4 -0
- data/lib/plutonium/resource/query_object.rb +3 -5
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- metadata +64 -7
- data/lib/generators/pu/res/entity/entity_generator.rb +0 -158
- data/lib/generators/pu/rodauth/customer_generator.rb +0 -101
- data/public/plutonium-assets/plutonium-logo-original.png +0 -0
- data/public/plutonium-assets/plutonium-logo-white.png +0 -0
- data/public/plutonium-assets/plutonium-logo.png +0 -0
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rails/generators/named_base"
|
|
4
|
-
require_relative "../../lib/plutonium_generators"
|
|
5
|
-
|
|
6
|
-
module Pu
|
|
7
|
-
module Res
|
|
8
|
-
class EntityGenerator < ::Rails::Generators::NamedBase
|
|
9
|
-
include PlutoniumGenerators::Generator
|
|
10
|
-
|
|
11
|
-
desc "Generate an entity model for customer accounts"
|
|
12
|
-
|
|
13
|
-
class_option :model, type: :boolean, default: true
|
|
14
|
-
class_option :allow_signup, type: :boolean, default: true,
|
|
15
|
-
desc: "Whether to allow customer to sign up to the platform"
|
|
16
|
-
class_option :auth_account, type: :string,
|
|
17
|
-
desc: "Specify the authentication account name", required: true
|
|
18
|
-
|
|
19
|
-
def start
|
|
20
|
-
ensure_customer_model_exists! if behavior == :invoke
|
|
21
|
-
generate_entity_resource
|
|
22
|
-
generate_membership_resource
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
def ensure_customer_model_exists!
|
|
28
|
-
customer_model_path = File.join("app", "models", "#{normalized_auth_account_name}.rb")
|
|
29
|
-
unless File.exist?(customer_model_path)
|
|
30
|
-
raise "Customer model '#{normalized_auth_account_name}' does not exist. Please create it first."
|
|
31
|
-
end
|
|
32
|
-
rescue => e
|
|
33
|
-
exception "#{self.class} failed:", e
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def generate_entity_resource
|
|
37
|
-
Rails::Generators.invoke(
|
|
38
|
-
"pu:res:scaffold",
|
|
39
|
-
[
|
|
40
|
-
normalized_name,
|
|
41
|
-
"name:string",
|
|
42
|
-
"--model",
|
|
43
|
-
("--force" if options[:force]),
|
|
44
|
-
("--skip" if options[:skip]),
|
|
45
|
-
"--dest=#{selected_destination_feature}"
|
|
46
|
-
].compact,
|
|
47
|
-
behavior: behavior,
|
|
48
|
-
destination_root: destination_root
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
add_unique_index_to_migration(normalized_name, [:name])
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def generate_membership_resource
|
|
55
|
-
Rails::Generators.invoke(
|
|
56
|
-
"pu:res:scaffold",
|
|
57
|
-
[
|
|
58
|
-
normalized_entity_membership_name,
|
|
59
|
-
*membership_attributes,
|
|
60
|
-
"--model",
|
|
61
|
-
("--force" if options[:force]),
|
|
62
|
-
("--skip" if options[:skip]),
|
|
63
|
-
"--dest=#{selected_destination_feature}"
|
|
64
|
-
].compact,
|
|
65
|
-
behavior: behavior,
|
|
66
|
-
destination_root: destination_root
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
add_unique_index_to_migration(
|
|
70
|
-
normalized_entity_membership_name,
|
|
71
|
-
["#{normalized_name}_id", "#{normalized_auth_account_name}_id"]
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
add_default_to_role_column
|
|
75
|
-
add_role_enum_to_model
|
|
76
|
-
add_unique_validation_to_model
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private
|
|
80
|
-
|
|
81
|
-
def selected_destination_feature = "main_app"
|
|
82
|
-
|
|
83
|
-
def normalized_name = name.underscore
|
|
84
|
-
|
|
85
|
-
def normalized_entity_membership_name
|
|
86
|
-
"#{normalized_name}_#{normalized_auth_account_name}"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def normalized_auth_account_name = options[:auth_account].underscore
|
|
90
|
-
|
|
91
|
-
def add_unique_index_to_migration(model_name, index_columns)
|
|
92
|
-
migration_dir = File.join("db", "migrate")
|
|
93
|
-
migration_file = Dir[File.join(migration_dir, "*_create_#{model_name.pluralize}.rb")].first
|
|
94
|
-
|
|
95
|
-
modify_file_if_exists(migration_file) do |file|
|
|
96
|
-
index_definition = build_index_definition(model_name, index_columns)
|
|
97
|
-
insert_into_file migration_file, indent(index_definition, 4), before: /^ end\s*$/
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def build_index_definition(model_name, index_columns)
|
|
102
|
-
table_name = model_name.pluralize
|
|
103
|
-
|
|
104
|
-
case index_columns
|
|
105
|
-
when Array
|
|
106
|
-
if index_columns.size == 1
|
|
107
|
-
"add_index :#{table_name}, :#{index_columns.first}, unique: true\n"
|
|
108
|
-
else
|
|
109
|
-
column_list = index_columns.map { |col| ":#{col}" }.join(", ")
|
|
110
|
-
"add_index :#{table_name}, [#{column_list}], unique: true\n"
|
|
111
|
-
end
|
|
112
|
-
else
|
|
113
|
-
"add_index :#{table_name}, :#{index_columns}, unique: true\n"
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def membership_attributes
|
|
118
|
-
[
|
|
119
|
-
"#{normalized_name}:references",
|
|
120
|
-
"#{normalized_auth_account_name}:references",
|
|
121
|
-
"role:integer"
|
|
122
|
-
]
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def add_default_to_role_column
|
|
126
|
-
migration_dir = File.join("db", "migrate")
|
|
127
|
-
migration_file = Dir[File.join(migration_dir, "*_create_#{normalized_entity_membership_name.pluralize}.rb")].first
|
|
128
|
-
|
|
129
|
-
modify_file_if_exists(migration_file) do |file|
|
|
130
|
-
gsub_file file, /t\.integer :role, null: false/, "t.integer :role, null: false, default: 0 # Member by default"
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def add_role_enum_to_model
|
|
135
|
-
model_file = File.join("app", "models", "#{normalized_entity_membership_name}.rb")
|
|
136
|
-
|
|
137
|
-
modify_file_if_exists(model_file) do |file|
|
|
138
|
-
enum_definition = "\nenum :role, member: 0, owner: 1"
|
|
139
|
-
insert_into_file file, indent(enum_definition, 2), before: /^\s*# add model configurations above\./
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def add_unique_validation_to_model
|
|
144
|
-
model_file = File.join("app", "models", "#{normalized_entity_membership_name}.rb")
|
|
145
|
-
|
|
146
|
-
modify_file_if_exists(model_file) do |file|
|
|
147
|
-
validation_definition = "validates :#{normalized_auth_account_name}, uniqueness: {scope: :#{normalized_name}_id, message: \"is already a member of this entity\"}\n"
|
|
148
|
-
insert_into_file file, indent(validation_definition, 2), before: /^\s*# add validations above\./
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def modify_file_if_exists(file_path)
|
|
153
|
-
return unless file_path && File.exist?(file_path)
|
|
154
|
-
yield(file_path)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
end
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
return unless defined?(Rodauth::Rails)
|
|
4
|
-
|
|
5
|
-
require "rails/generators/named_base"
|
|
6
|
-
require_relative "../lib/plutonium_generators"
|
|
7
|
-
|
|
8
|
-
module Pu
|
|
9
|
-
module Rodauth
|
|
10
|
-
class CustomerGenerator < ::Rails::Generators::NamedBase
|
|
11
|
-
include PlutoniumGenerators::Concerns::Logger
|
|
12
|
-
|
|
13
|
-
source_root File.expand_path("templates", __dir__)
|
|
14
|
-
|
|
15
|
-
desc "Generate a rodauth-rails account optimized for customer-based tasks"
|
|
16
|
-
|
|
17
|
-
class_option :allow_signup, type: :boolean, default: true,
|
|
18
|
-
desc: "Whether to allow customer to sign up to the platform"
|
|
19
|
-
|
|
20
|
-
class_option :entity, default: "Entity",
|
|
21
|
-
desc: "Generate an entity model for customer accounts. Defaults to 'Entity'",
|
|
22
|
-
aliases: ["--entity", "-e"]
|
|
23
|
-
|
|
24
|
-
def start
|
|
25
|
-
create_customer_account
|
|
26
|
-
create_entity_model_and_membership
|
|
27
|
-
configure_model_relationships
|
|
28
|
-
rescue => e
|
|
29
|
-
exception "#{self.class} failed:", e
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def create_customer_account
|
|
35
|
-
invoke "pu:rodauth:account", [name],
|
|
36
|
-
defaults: false,
|
|
37
|
-
**customer_features,
|
|
38
|
-
force: options[:force],
|
|
39
|
-
skip: options[:skip],
|
|
40
|
-
lint: true
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def create_entity_model_and_membership
|
|
44
|
-
invoke "pu:res:entity", [normalized_entity_name],
|
|
45
|
-
auth_account: normalized_name,
|
|
46
|
-
force: options[:force],
|
|
47
|
-
skip: options[:skip]
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def configure_model_relationships
|
|
51
|
-
entity_model_path = File.join("app", "models", "#{normalized_entity_name}.rb")
|
|
52
|
-
if File.exist?(entity_model_path)
|
|
53
|
-
insert_into_file entity_model_path, <<~RUBY + " ", before: /# add has_many associations above\.\n/
|
|
54
|
-
has_many :#{normalized_entity_membership_name.pluralize}
|
|
55
|
-
has_many :#{normalized_name.pluralize}, through: :#{normalized_entity_membership_name.pluralize}
|
|
56
|
-
RUBY
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
customer_model_path = File.join("app", "models", "#{normalized_name}.rb")
|
|
60
|
-
if File.exist?(customer_model_path)
|
|
61
|
-
insert_into_file customer_model_path, <<~RUBY + " ", before: /# add has_many associations above\.\n/
|
|
62
|
-
has_many :#{normalized_entity_membership_name.pluralize}
|
|
63
|
-
has_many :#{normalized_entity_name.pluralize}, through: :#{normalized_entity_membership_name.pluralize}
|
|
64
|
-
RUBY
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
def customer_features
|
|
71
|
-
features = %i[
|
|
72
|
-
login
|
|
73
|
-
remember
|
|
74
|
-
logout
|
|
75
|
-
create_account
|
|
76
|
-
verify_account
|
|
77
|
-
verify_account_grace_period
|
|
78
|
-
reset_password
|
|
79
|
-
reset_password_notify
|
|
80
|
-
change_login
|
|
81
|
-
verify_login_change
|
|
82
|
-
change_password
|
|
83
|
-
change_password_notify
|
|
84
|
-
case_insensitive_login
|
|
85
|
-
internal_request
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
features.delete(:create_account) unless options[:allow_signup]
|
|
89
|
-
features.map { |feature| [feature, true] }.to_h
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def normalized_name = name.underscore
|
|
93
|
-
|
|
94
|
-
def normalized_entity_name = options[:entity].underscore
|
|
95
|
-
|
|
96
|
-
def normalized_entity_membership_name
|
|
97
|
-
"#{normalized_entity_name.underscore}_#{normalized_name}"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|