ditty 0.8.0 → 0.10.2
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/.env.test +2 -0
- data/.gitignore +3 -0
- data/.pryrc +2 -0
- data/.rubocop.yml +23 -4
- data/.travis.yml +4 -8
- data/CNAME +1 -0
- data/Dockerfile +18 -0
- data/Gemfile.ci +0 -17
- data/Rakefile +2 -2
- data/_config.yml +1 -0
- data/config.ru +4 -4
- data/ditty.gemspec +28 -18
- data/docs/CNAME +1 -0
- data/docs/_config.yml +1 -0
- data/docs/index.md +34 -0
- data/exe/ditty +2 -0
- data/lib/ditty/cli.rb +41 -5
- data/lib/ditty/components/{app.rb → ditty.rb} +18 -16
- data/lib/ditty/controllers/{application.rb → application_controller.rb} +63 -34
- data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +4 -2
- data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +22 -18
- data/lib/ditty/controllers/{component.rb → component_controller.rb} +23 -20
- data/lib/ditty/controllers/{main.rb → main_controller.rb} +6 -2
- data/lib/ditty/controllers/roles_controller.rb +23 -0
- data/lib/ditty/controllers/user_login_traits_controller.rb +46 -0
- data/lib/ditty/controllers/{users.rb → users_controller.rb} +13 -11
- data/lib/ditty/db.rb +7 -5
- data/lib/ditty/emails/base.rb +37 -32
- data/lib/ditty/generators/crud_generator.rb +114 -0
- data/lib/ditty/generators/migration_generator.rb +26 -0
- data/lib/ditty/generators/project_generator.rb +52 -0
- data/lib/ditty/helpers/component.rb +2 -1
- data/lib/ditty/helpers/pundit.rb +24 -8
- data/lib/ditty/helpers/response.rb +15 -13
- data/lib/ditty/helpers/views.rb +28 -6
- data/lib/ditty/listener.rb +6 -4
- data/lib/ditty/memcached.rb +8 -0
- data/lib/ditty/middleware/accept_extension.rb +2 -2
- data/lib/ditty/middleware/error_catchall.rb +2 -2
- data/lib/ditty/models/base.rb +9 -0
- data/lib/ditty/models/identity.rb +11 -7
- data/lib/ditty/models/role.rb +1 -0
- data/lib/ditty/models/user.rb +23 -2
- data/lib/ditty/policies/role_policy.rb +1 -1
- data/lib/ditty/policies/user_login_trait_policy.rb +1 -1
- data/lib/ditty/policies/user_policy.rb +1 -1
- data/lib/ditty/services/authentication.rb +27 -16
- data/lib/ditty/services/email.rb +19 -15
- data/lib/ditty/services/logger.rb +26 -20
- data/lib/ditty/services/pagination_wrapper.rb +7 -5
- data/lib/ditty/services/settings.rb +7 -6
- data/lib/ditty/tasks/ditty.rake +19 -1
- data/lib/ditty/tasks/omniauth-ldap.rake +2 -2
- data/lib/ditty/templates/.gitignore +5 -0
- data/lib/ditty/templates/.rspec +2 -0
- data/lib/ditty/templates/.rubocop.yml +7 -0
- data/lib/ditty/templates/Rakefile +12 -0
- data/lib/ditty/templates/application.rb +12 -0
- data/lib/ditty/templates/config.ru +37 -0
- data/lib/ditty/templates/controller.rb.erb +64 -0
- data/lib/ditty/templates/env.example +4 -0
- data/lib/ditty/templates/lib/project.rb.erb +5 -0
- data/lib/ditty/templates/logs/.empty_directory +0 -0
- data/lib/ditty/templates/migration.rb.erb +7 -0
- data/lib/ditty/templates/model.rb.erb +26 -0
- data/lib/ditty/templates/pids/.empty_directory +0 -0
- data/lib/ditty/templates/policy.rb.erb +48 -0
- data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
- data/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
- data/lib/ditty/templates/public/css/styles.css +13 -0
- data/lib/ditty/templates/public/favicon.ico +0 -0
- data/{public → lib/ditty/templates/public}/images/apple-icon.png +0 -0
- data/{public → lib/ditty/templates/public}/images/favicon-16x16.png +0 -0
- data/{public → lib/ditty/templates/public}/images/favicon-32x32.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-1x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-2x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-4x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/mstile-150x150.png +0 -0
- data/{public → lib/ditty/templates/public}/images/safari-pinned-tab.svg +0 -0
- data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
- data/lib/ditty/templates/public/js/scripts.js +1 -0
- data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
- data/lib/ditty/templates/settings.yml.erb +29 -0
- data/lib/ditty/templates/sidekiq.rb +18 -0
- data/lib/ditty/templates/sidekiq.yml +9 -0
- data/lib/ditty/templates/spec_helper.rb +43 -0
- data/lib/ditty/templates/type.rb.erb +21 -0
- data/lib/ditty/templates/views/display.haml.tt +20 -0
- data/lib/ditty/templates/views/edit.haml.tt +10 -0
- data/lib/ditty/templates/views/form.haml.tt +11 -0
- data/lib/ditty/templates/views/index.haml.tt +29 -0
- data/lib/ditty/templates/views/new.haml.tt +10 -0
- data/lib/ditty/version.rb +1 -1
- data/lib/ditty.rb +6 -4
- data/lib/rubocop/cop/ditty/call_services_directly.rb +2 -2
- data/migrate/20181209_add_user_login_traits.rb +4 -4
- data/migrate/20190220_add_parent_id_to_roles.rb +9 -0
- data/spec/ditty/api_spec.rb +51 -0
- data/spec/ditty/controllers/roles_spec.rb +67 -0
- data/spec/ditty/controllers/user_login_traits_spec.rb +72 -0
- data/spec/ditty/controllers/users_spec.rb +72 -0
- data/spec/ditty/emails/base_spec.rb +76 -0
- data/spec/ditty/emails/forgot_password_spec.rb +20 -0
- data/spec/ditty/helpers/component_spec.rb +85 -0
- data/spec/ditty/models/user_spec.rb +36 -0
- data/spec/ditty/services/email_spec.rb +36 -0
- data/spec/ditty/services/logger_spec.rb +68 -0
- data/spec/ditty/services/settings_spec.rb +63 -0
- data/spec/ditty_spec.rb +9 -0
- data/spec/factories.rb +46 -0
- data/spec/fixtures/logger.yml +17 -0
- data/spec/fixtures/section.yml +3 -0
- data/spec/fixtures/settings.yml +8 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/api_shared_examples.rb +250 -0
- data/spec/support/crud_shared_examples.rb +145 -0
- data/views/403.haml +1 -1
- data/views/404.haml +2 -4
- data/views/500.haml +11 -0
- data/views/audit_logs/index.haml +32 -33
- data/views/auth/forgot_password.haml +32 -16
- data/views/auth/identity.haml +14 -13
- data/views/auth/ldap.haml +2 -2
- data/views/auth/login.haml +23 -17
- data/views/auth/register.haml +20 -18
- data/views/auth/register_identity.haml +27 -12
- data/views/auth/reset_password.haml +36 -19
- data/views/blank.haml +43 -0
- data/views/embedded.haml +17 -11
- data/views/index.haml +1 -1
- data/views/layout.haml +45 -30
- data/views/partials/actions.haml +15 -14
- data/views/partials/content_tag.haml +0 -0
- data/views/partials/delete_form.haml +1 -1
- data/views/partials/filter_control.haml +2 -2
- data/views/partials/footer.haml +6 -5
- data/views/partials/form_control.haml +19 -12
- data/views/partials/form_tag.haml +1 -1
- data/views/partials/navitems.haml +42 -0
- data/views/partials/notifications.haml +12 -8
- data/views/partials/pager.haml +44 -25
- data/views/partials/search.haml +15 -11
- data/views/partials/sidebar.haml +15 -37
- data/views/partials/sort_ui.haml +2 -0
- data/views/partials/topbar.haml +53 -0
- data/views/partials/user_associations.haml +32 -0
- data/views/quick_start.haml +23 -0
- data/views/roles/display.haml +27 -6
- data/views/roles/edit.haml +3 -3
- data/views/roles/form.haml +1 -0
- data/views/roles/index.haml +23 -16
- data/views/roles/new.haml +2 -2
- data/views/user_login_traits/display.haml +4 -4
- data/views/user_login_traits/edit.haml +3 -3
- data/views/user_login_traits/index.haml +23 -25
- data/views/user_login_traits/new.haml +2 -2
- data/views/users/display.haml +14 -15
- data/views/users/edit.haml +3 -3
- data/views/users/form.haml +0 -0
- data/views/users/index.haml +31 -24
- data/views/users/login_traits.haml +6 -8
- data/views/users/new.haml +2 -2
- data/views/users/profile.haml +15 -15
- data/views/users/user.haml +1 -1
- metadata +271 -63
- data/lib/ditty/controllers/roles.rb +0 -13
- data/lib/ditty/controllers/user_login_traits.rb +0 -18
- data/views/partials/navbar.haml +0 -22
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/application_controller'
|
|
4
4
|
require 'ditty/models/role'
|
|
5
5
|
require 'ditty/models/user'
|
|
6
|
+
require 'ditty/services/settings'
|
|
6
7
|
|
|
7
8
|
module Ditty
|
|
8
|
-
class
|
|
9
|
+
class MainController < ApplicationController
|
|
9
10
|
set track_actions: true
|
|
10
11
|
|
|
11
12
|
before '/' do
|
|
@@ -17,6 +18,9 @@ module Ditty
|
|
|
17
18
|
|
|
18
19
|
# Home Page
|
|
19
20
|
get '/' do
|
|
21
|
+
home_page = Services::Settings['ditty.home_page']
|
|
22
|
+
redirect "#{settings.map_path}#{home_page}" if home_page
|
|
23
|
+
|
|
20
24
|
authenticate!
|
|
21
25
|
haml :index, locals: { title: 'Home' }
|
|
22
26
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ditty/controllers/component_controller'
|
|
4
|
+
require 'ditty/models/role'
|
|
5
|
+
require 'ditty/policies/role_policy'
|
|
6
|
+
|
|
7
|
+
module Ditty
|
|
8
|
+
class RolesController < ::Ditty::ComponentController
|
|
9
|
+
SEARCHABLE = %i[name].freeze
|
|
10
|
+
|
|
11
|
+
set model_class: Role
|
|
12
|
+
|
|
13
|
+
helpers do
|
|
14
|
+
def parent_options(entity)
|
|
15
|
+
return policy_scope(::Ditty::Role) if entity.new?
|
|
16
|
+
|
|
17
|
+
policy_scope(::Ditty::Role)
|
|
18
|
+
.exclude(id: [entity.id] + entity.descendants.map(&:id))
|
|
19
|
+
.order(:name)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ditty/controllers/component_controller'
|
|
4
|
+
require 'ditty/models/user_login_trait'
|
|
5
|
+
require 'ditty/policies/user_login_trait_policy'
|
|
6
|
+
|
|
7
|
+
module Ditty
|
|
8
|
+
class UserLoginTraitsController < ::Ditty::ComponentController
|
|
9
|
+
SEARCHABLE = %i[platform device browser ip_address].freeze
|
|
10
|
+
FILTERS = [
|
|
11
|
+
{ name: :user, field: 'user.email' },
|
|
12
|
+
{ name: :platform },
|
|
13
|
+
{ name: :device },
|
|
14
|
+
{ name: :browser }
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
set base_path: '/login-traits'
|
|
18
|
+
set model_class: UserLoginTrait
|
|
19
|
+
set heading: 'Login'
|
|
20
|
+
# set track_actions: true
|
|
21
|
+
|
|
22
|
+
helpers do
|
|
23
|
+
def user_options
|
|
24
|
+
policy_scope(::Ditty::User).as_hash(:email, :email)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def platform_options
|
|
28
|
+
policy_scope(::Ditty::UserLoginTrait).select(:platform).distinct.as_hash(:platform, :platform)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def device_options
|
|
32
|
+
policy_scope(::Ditty::UserLoginTrait).select(:device).distinct.as_hash(:device, :device)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def browser_options
|
|
36
|
+
policy_scope(::Ditty::UserLoginTrait).select(:browser).distinct.as_hash(:browser, :browser)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def list
|
|
41
|
+
return super if params[:sort]
|
|
42
|
+
|
|
43
|
+
super.order(:updated_at).reverse
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/component_controller'
|
|
4
4
|
require 'ditty/models/user'
|
|
5
5
|
require 'ditty/models/user_login_trait'
|
|
6
6
|
require 'ditty/policies/user_policy'
|
|
@@ -8,7 +8,7 @@ require 'ditty/models/identity'
|
|
|
8
8
|
require 'ditty/policies/identity_policy'
|
|
9
9
|
|
|
10
10
|
module Ditty
|
|
11
|
-
class
|
|
11
|
+
class UsersController < ::Ditty::ComponentController
|
|
12
12
|
SEARCHABLE = %i[name surname email].freeze
|
|
13
13
|
|
|
14
14
|
set model_class: User
|
|
@@ -28,8 +28,8 @@ module Ditty
|
|
|
28
28
|
|
|
29
29
|
locals = { title: heading(:new) }
|
|
30
30
|
|
|
31
|
-
user_params =
|
|
32
|
-
identity_params =
|
|
31
|
+
user_params = permitted_parameters(User, :create)
|
|
32
|
+
identity_params = permitted_parameters(Identity, :create)
|
|
33
33
|
user_params['email'] = identity_params['username']
|
|
34
34
|
roles = user_params.delete('role_id')
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ module Ditty
|
|
|
38
38
|
|
|
39
39
|
DB.transaction(isolation: :serializable) do
|
|
40
40
|
begin
|
|
41
|
-
identity.
|
|
41
|
+
identity.save_changes
|
|
42
42
|
rescue Sequel::ValidationFailed
|
|
43
43
|
raise unless request.accept? 'text/html'
|
|
44
44
|
|
|
@@ -46,7 +46,7 @@ module Ditty
|
|
|
46
46
|
locals = { title: heading(:new), entity: user, identity: identity }
|
|
47
47
|
return haml(:"#{view_location}/new", locals: locals)
|
|
48
48
|
end
|
|
49
|
-
user.
|
|
49
|
+
user.save_changes
|
|
50
50
|
user.add_identity identity
|
|
51
51
|
|
|
52
52
|
roles&.each do |role_id|
|
|
@@ -55,7 +55,7 @@ module Ditty
|
|
|
55
55
|
user.check_roles
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
broadcast(:component_create, target: self)
|
|
58
|
+
broadcast(:component_create, target: self, entity: user)
|
|
59
59
|
create_response(user)
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -65,10 +65,10 @@ module Ditty
|
|
|
65
65
|
halt 404 unless entity
|
|
66
66
|
authorize entity, :update
|
|
67
67
|
|
|
68
|
-
values =
|
|
68
|
+
values = permitted_parameters(settings.model_class, :update)
|
|
69
69
|
roles = values.delete('role_id')
|
|
70
70
|
entity.set values
|
|
71
|
-
entity.
|
|
71
|
+
entity.save_changes # Will trigger a Sequel::ValidationFailed exception if the model is incorrect
|
|
72
72
|
|
|
73
73
|
if roles
|
|
74
74
|
entity.remove_all_roles
|
|
@@ -94,9 +94,10 @@ module Ditty
|
|
|
94
94
|
return redirect back
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
values =
|
|
97
|
+
values = permitted_parameters(Identity, :create)
|
|
98
98
|
identity.set values
|
|
99
|
-
if identity.valid?
|
|
99
|
+
if identity.valid?
|
|
100
|
+
identity.save_changes
|
|
100
101
|
broadcast(:identity_update_password, target: self)
|
|
101
102
|
flash[:success] = 'Password Updated'
|
|
102
103
|
redirect back
|
|
@@ -129,6 +130,7 @@ module Ditty
|
|
|
129
130
|
halt 404 unless entity
|
|
130
131
|
authorize entity, :read
|
|
131
132
|
|
|
133
|
+
flash[:redirect_to] = request.path
|
|
132
134
|
haml :"#{view_location}/profile", locals: { entity: entity, identity: entity.identity.first, title: 'My Account' }
|
|
133
135
|
end
|
|
134
136
|
end
|
data/lib/ditty/db.rb
CHANGED
|
@@ -8,7 +8,7 @@ require 'active_support/core_ext/object/blank'
|
|
|
8
8
|
pool_timeout = (ENV['DB_POOL_TIMEOUT'] || 5).to_i
|
|
9
9
|
|
|
10
10
|
if defined? DB
|
|
11
|
-
Ditty::Services::Logger.
|
|
11
|
+
::Ditty::Services::Logger.warn 'Database connection already set up'
|
|
12
12
|
elsif ENV['DATABASE_URL'].blank? == false
|
|
13
13
|
# Delete DATABASE_URL from the environment, so it isn't accidently
|
|
14
14
|
# passed to subprocesses. DATABASE_URL may contain passwords.
|
|
@@ -18,14 +18,16 @@ elsif ENV['DATABASE_URL'].blank? == false
|
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
DB.sql_log_level = (ENV['SEQUEL_LOGGING_LEVEL'] || :debug).to_sym
|
|
21
|
-
DB.loggers << Ditty::Services::Logger
|
|
21
|
+
DB.loggers << ::Ditty::Services::Logger if ENV['DB_DEBUG'].to_i == 1
|
|
22
22
|
DB.extension(:pagination)
|
|
23
23
|
DB.extension(:schema_caching)
|
|
24
24
|
DB.load_schema_cache?('./config/schema.dump')
|
|
25
25
|
|
|
26
|
-
Sequel::Model.plugin :
|
|
27
|
-
Sequel::Model.plugin :
|
|
26
|
+
Sequel::Model.plugin :auto_validations
|
|
27
|
+
Sequel::Model.plugin :string_stripper
|
|
28
28
|
Sequel::Model.plugin :timestamps, update_on_create: true
|
|
29
|
+
Sequel::Model.plugin :update_or_create
|
|
30
|
+
Sequel::Model.plugin :validation_helpers
|
|
29
31
|
else
|
|
30
|
-
Ditty::Services::Logger.
|
|
32
|
+
::Ditty::Services::Logger.error 'No database connection set up'
|
|
31
33
|
end
|
data/lib/ditty/emails/base.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'haml'
|
|
4
|
-
require 'ditty/components/
|
|
4
|
+
require 'ditty/components/ditty'
|
|
5
5
|
|
|
6
6
|
module Ditty
|
|
7
7
|
module Emails
|
|
@@ -23,7 +23,10 @@ module Ditty
|
|
|
23
23
|
@locals[param] ||= options[param]
|
|
24
24
|
mail.send(param, options[param])
|
|
25
25
|
end
|
|
26
|
-
|
|
26
|
+
html = content
|
|
27
|
+
mail.html_part do
|
|
28
|
+
body html
|
|
29
|
+
end
|
|
27
30
|
mail.deliver!
|
|
28
31
|
end
|
|
29
32
|
|
|
@@ -34,50 +37,52 @@ module Ditty
|
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def respond_to_missing?(method, _include_private = false)
|
|
37
|
-
mail.respond_to?
|
|
40
|
+
return true if mail.respond_to?(method)
|
|
41
|
+
|
|
42
|
+
super
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
private
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
def content
|
|
48
|
+
result = Haml::Engine.new(content_haml).render(Object.new, locals)
|
|
49
|
+
return result unless options[:layout]
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
Haml::Engine.new(layout_haml).render(Object.new, locals.merge(content: result))
|
|
52
|
+
end
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
def content_haml
|
|
55
|
+
read_template(options[:view])
|
|
56
|
+
end
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
def layout_haml
|
|
59
|
+
read_template("layouts/#{options[:layout]}") if options[:layout]
|
|
60
|
+
end
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
def read_template(template)
|
|
63
|
+
File.read(find_template("emails/#{template}"))
|
|
64
|
+
end
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
def base_options
|
|
67
|
+
{ subject: '(No Subject)', from: 'no-reply@ditty.io', view: :base, content_type: 'text/html; charset=UTF-8' }
|
|
68
|
+
end
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
def find_template(file)
|
|
71
|
+
template = File.expand_path("./views/#{file}.haml")
|
|
72
|
+
return template if File.file? template
|
|
68
73
|
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
template = File.expand_path("./#{file}.haml", ::Ditty::Ditty.view_folder)
|
|
75
|
+
return template if File.file? template
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
file
|
|
78
|
+
end
|
|
74
79
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
class << self
|
|
81
|
+
def deliver!(to = nil, options = {})
|
|
82
|
+
locals = options[:locals] || {}
|
|
83
|
+
new(options).deliver!(to, locals)
|
|
84
|
+
end
|
|
79
85
|
end
|
|
80
|
-
end
|
|
81
86
|
end
|
|
82
87
|
end
|
|
83
88
|
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor/group'
|
|
4
|
+
require 'active_support/inflector'
|
|
5
|
+
|
|
6
|
+
module Ditty
|
|
7
|
+
module Generators
|
|
8
|
+
class CrudGenerator < Thor::Group
|
|
9
|
+
include Thor::Actions
|
|
10
|
+
attr_reader :namespace, :folder, :views_folder, :controller_name, :model_name, :policy_name # , :file_name
|
|
11
|
+
|
|
12
|
+
desc 'Create a CRUD Endpoint including the Model, Controller, Policy, Views and GraphQL Types'
|
|
13
|
+
argument :name, type: :string, desc: 'Name of the Model, eg. MyApp::User'
|
|
14
|
+
|
|
15
|
+
# --no-views make views optional
|
|
16
|
+
class_option :views, type: :boolean, default: true, desc: 'Generate views for controller'
|
|
17
|
+
|
|
18
|
+
def self.source_root
|
|
19
|
+
File.dirname(__FILE__)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def setup
|
|
23
|
+
@namespace = name.deconstantize
|
|
24
|
+
@folder = namespace.underscore
|
|
25
|
+
@model_name = name.demodulize
|
|
26
|
+
@views_folder = File.join('views', model_name.pluralize.underscore)
|
|
27
|
+
@controller_name = "#{model_name.pluralize}Controller"
|
|
28
|
+
@policy_name = "#{model_name}Policy"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def create_model
|
|
32
|
+
filename = File.join("lib/#{folder}/models", "#{model_name.underscore}.rb")
|
|
33
|
+
template '../templates/model.rb.erb', filename
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
puts "Could not generate model for #{model_name}: #{e.message}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create_controller
|
|
39
|
+
filename = File.join("lib/#{folder}/controllers", "#{controller_name.underscore}.rb")
|
|
40
|
+
template '../templates/controller.rb.erb', filename
|
|
41
|
+
# TODO: Insert the route into the component file
|
|
42
|
+
# insert_into_file 'config.ru', "use #{class_name}\n", after: 'run ApplicationController\n'
|
|
43
|
+
rescue StandardError => e
|
|
44
|
+
puts "Could not generate controller for #{model_name}: #{e.message}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def create_policy
|
|
48
|
+
filename = File.join("lib/#{folder}/policies", "#{policy_name.underscore}.rb")
|
|
49
|
+
template '../templates/policy.rb.erb', filename
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
puts "Could not generate policy for #{model_name}: #{e.message}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_type
|
|
55
|
+
filename = File.join("lib/#{folder}/types", "#{model_name.underscore}_type.rb")
|
|
56
|
+
template '../templates/type.rb.erb', filename
|
|
57
|
+
rescue StandardError => e
|
|
58
|
+
puts "Could not generate type for #{model_name}: #{e.message}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def create_views
|
|
62
|
+
return unless options[:views]
|
|
63
|
+
|
|
64
|
+
directory '../templates/views', views_folder
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def meta_columns
|
|
70
|
+
%i[id guid slug created_at updated_at]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def columns
|
|
74
|
+
require "#{folder}/models/#{model_name.underscore}"
|
|
75
|
+
name.constantize.columns
|
|
76
|
+
rescue StandardError
|
|
77
|
+
[]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def schema
|
|
81
|
+
require "#{folder}/models/#{model_name.underscore}"
|
|
82
|
+
name.constantize.db_schema
|
|
83
|
+
rescue StandardError
|
|
84
|
+
[]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def many_to_ones
|
|
88
|
+
DB.foreign_key_list(model_name.underscore.pluralize)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def name_column(table)
|
|
92
|
+
candidates = DB.schema(table.to_sym).to_h.keys - DB.foreign_key_list(table.to_sym).map do |e|
|
|
93
|
+
e[:columns]
|
|
94
|
+
end.flatten
|
|
95
|
+
(candidates - meta_columns).first
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def graphql_types
|
|
99
|
+
@graphql_types ||= Hash.new('String').merge(
|
|
100
|
+
integer: 'Integer',
|
|
101
|
+
boolean: 'Boolean',
|
|
102
|
+
datetime: 'GraphQL::Types::ISO8601DateTime'
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def input_types
|
|
107
|
+
@input_types ||= Hash.new('text').merge(
|
|
108
|
+
integer: 'number',
|
|
109
|
+
datetime: 'date'
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor/group'
|
|
4
|
+
require 'active_support/inflector'
|
|
5
|
+
|
|
6
|
+
module Ditty
|
|
7
|
+
module Generators
|
|
8
|
+
class MigrationGenerator < Thor::Group
|
|
9
|
+
include Thor::Actions
|
|
10
|
+
|
|
11
|
+
attr_reader :namespace, :folder
|
|
12
|
+
|
|
13
|
+
desc 'Creates a new Sequel migration for the current project'
|
|
14
|
+
argument :name, type: :string, desc: 'Name of the migration'
|
|
15
|
+
|
|
16
|
+
def self.source_root
|
|
17
|
+
File.expand_path('../templates', __dir__)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create_model
|
|
21
|
+
filename = File.join('migrations', "#{Time.now.strftime('%Y%m%d')}_#{name.underscore}.rb")
|
|
22
|
+
template '../templates/migration.rb.erb', filename
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|