ditty 0.8.0 → 0.9.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/.gitignore +2 -0
- data/.pryrc +2 -0
- data/.rubocop.yml +1 -1
- data/.travis.yml +5 -4
- data/CNAME +1 -0
- data/Dockerfile +18 -0
- data/Gemfile.ci +0 -2
- data/Rakefile +2 -2
- data/_config.yml +1 -0
- data/config.ru +4 -4
- data/ditty.gemspec +9 -3
- 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.rb +4 -2
- data/lib/ditty/cli.rb +28 -4
- data/lib/ditty/components/{app.rb → ditty.rb} +19 -14
- data/lib/ditty/controllers/{application.rb → application_controller.rb} +58 -29
- data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +2 -2
- data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +17 -16
- data/lib/ditty/controllers/{component.rb → component_controller.rb} +19 -18
- 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.rb → user_login_traits_controller.rb} +4 -3
- data/lib/ditty/controllers/{users.rb → users_controller.rb} +11 -10
- data/lib/ditty/db.rb +4 -3
- data/lib/ditty/emails/base.rb +5 -2
- data/lib/ditty/generators/crud_generator.rb +104 -0
- data/lib/ditty/generators/migration_generator.rb +26 -0
- data/lib/ditty/generators/project_generator.rb +51 -0
- data/lib/ditty/helpers/component.rb +2 -1
- data/lib/ditty/helpers/pundit.rb +20 -4
- data/lib/ditty/helpers/response.rb +20 -13
- data/lib/ditty/helpers/views.rb +7 -3
- data/lib/ditty/listener.rb +5 -3
- 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 +4 -0
- data/lib/ditty/models/role.rb +1 -0
- data/lib/ditty/models/user.rb +14 -1
- data/lib/ditty/policies/role_policy.rb +1 -1
- data/lib/ditty/policies/user_login_trait_policy.rb +1 -1
- data/lib/ditty/services/authentication.rb +11 -10
- data/lib/ditty/services/email.rb +8 -4
- data/lib/ditty/services/logger.rb +1 -1
- data/lib/ditty/tasks/ditty.rake +17 -0
- 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 +58 -0
- data/lib/ditty/templates/env.example +4 -0
- data/lib/ditty/templates/lib/project.rb.erb +5 -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/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
- data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
- data/lib/ditty/templates/settings.yml.erb +18 -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/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/public/css/styles.css +13 -0
- data/public/js/scripts.js +1 -0
- data/views/404.haml +2 -4
- data/views/audit_logs/index.haml +32 -34
- data/views/auth/forgot_password.haml +27 -16
- data/views/auth/identity.haml +14 -13
- data/views/auth/ldap.haml +2 -2
- data/views/auth/login.haml +22 -17
- data/views/auth/register.haml +19 -18
- data/views/auth/register_identity.haml +27 -12
- data/views/auth/reset_password.haml +2 -2
- data/views/blank.haml +42 -0
- data/views/index.haml +1 -1
- data/views/layout.haml +37 -30
- data/views/partials/content_tag.haml +0 -0
- data/views/partials/delete_form.haml +1 -1
- data/views/partials/filter_control.haml +1 -1
- data/views/partials/footer.haml +5 -5
- data/views/partials/form_control.haml +19 -12
- data/views/partials/navitems.haml +44 -0
- data/views/partials/notifications.haml +12 -8
- data/views/partials/pager.haml +17 -17
- data/views/partials/search.haml +6 -7
- data/views/partials/sidebar.haml +15 -37
- data/views/partials/topbar.haml +68 -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 +4 -4
- data/views/user_login_traits/new.haml +2 -2
- data/views/users/display.haml +11 -12
- 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 +13 -13
- metadata +143 -15
- data/lib/ditty/controllers/roles.rb +0 -13
- data/views/partials/navbar.haml +0 -22
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/component_controller'
|
|
4
4
|
require 'ditty/models/audit_log'
|
|
5
5
|
require 'ditty/policies/audit_log_policy'
|
|
6
6
|
|
|
7
7
|
module Ditty
|
|
8
|
-
class
|
|
8
|
+
class AuditLogsController < ::Ditty::ComponentController
|
|
9
9
|
set model_class: AuditLog
|
|
10
10
|
|
|
11
11
|
SEARCHABLE = %i[details platform device browser ip_address].freeze
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/application_controller'
|
|
4
4
|
require 'ditty/services/email'
|
|
5
5
|
require 'securerandom'
|
|
6
6
|
|
|
7
7
|
module Ditty
|
|
8
|
-
class
|
|
8
|
+
class AuthController < ApplicationController
|
|
9
9
|
set track_actions: true
|
|
10
10
|
|
|
11
11
|
def redirect_path
|
|
12
12
|
return "#{settings.map_path}/" if omniauth_redirect_path.nil?
|
|
13
|
-
return "#{settings.map_path}/" if omniauth_redirect_path
|
|
13
|
+
return "#{settings.map_path}/" if omniauth_redirect_path.match? %r{/#{settings.map_path}/auth/?}
|
|
14
14
|
|
|
15
15
|
omniauth_redirect_path
|
|
16
16
|
end
|
|
@@ -67,7 +67,7 @@ module Ditty
|
|
|
67
67
|
authorize ::Ditty::Identity, :login
|
|
68
68
|
redirect settings.map_path if authenticated?
|
|
69
69
|
|
|
70
|
-
haml :'auth/login', locals: { title: 'Log In' }
|
|
70
|
+
haml :'auth/login', locals: { title: 'Log In' }, layout: :blank
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Custom login form for LDAP to allow CSRF checks. Set the `request_path` for
|
|
@@ -76,13 +76,13 @@ module Ditty
|
|
|
76
76
|
authorize ::Ditty::Identity, :login
|
|
77
77
|
redirect settings.map_path if authenticated?
|
|
78
78
|
|
|
79
|
-
haml :'auth/ldap', locals: { title: 'Company Log In' }
|
|
79
|
+
haml :'auth/ldap', locals: { title: 'Company Log In' }, layout: :blank
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
get '/forgot-password' do
|
|
83
83
|
authorize ::Ditty::Identity, :forgot_password
|
|
84
84
|
|
|
85
|
-
haml :'auth/forgot_password', locals: { title: 'Forgot your password?' }
|
|
85
|
+
haml :'auth/forgot_password', locals: { title: 'Forgot your password?' }, layout: :blank
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
post '/forgot-password' do
|
|
@@ -97,14 +97,14 @@ module Ditty
|
|
|
97
97
|
identity.update(reset_token: token, reset_requested: Time.now)
|
|
98
98
|
# Send Email
|
|
99
99
|
reset_url = "#{request.base_url}#{settings.map_path}/reset-password?token=#{token}"
|
|
100
|
-
Ditty::Services::Email.deliver(
|
|
100
|
+
::Ditty::Services::Email.deliver(
|
|
101
101
|
:forgot_password,
|
|
102
102
|
email,
|
|
103
103
|
locals: { identity: identity, reset_url: reset_url, request: request }
|
|
104
104
|
)
|
|
105
105
|
end
|
|
106
106
|
flash[:info] = 'An email was sent to the email provided with instructions on how to reset your password'
|
|
107
|
-
redirect
|
|
107
|
+
redirect "#{settings.map_path}/auth/login"
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
get '/reset-password' do
|
|
@@ -114,7 +114,7 @@ module Ditty
|
|
|
114
114
|
identity = Identity[reset_token: params[:token]]
|
|
115
115
|
halt 404 unless identity&.reset_requested && identity.reset_requested > (Time.now - (24 * 60 * 60))
|
|
116
116
|
|
|
117
|
-
haml :'auth/reset_password', locals: { title: 'Reset your password', identity: identity }
|
|
117
|
+
haml :'auth/reset_password', locals: { title: 'Reset your password', identity: identity }, layout: :blank
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
put '/reset-password' do
|
|
@@ -124,15 +124,15 @@ module Ditty
|
|
|
124
124
|
halt 404 unless identity
|
|
125
125
|
authorize identity, :reset_password
|
|
126
126
|
|
|
127
|
-
identity_params =
|
|
127
|
+
identity_params = permitted_parameters(Identity, :update)
|
|
128
128
|
identity.set identity_params.merge(reset_token: nil, reset_requested: nil)
|
|
129
|
-
if identity.valid? && identity.
|
|
129
|
+
if identity.valid? && identity.save_changes
|
|
130
130
|
broadcast(:identity_update_password, target: self)
|
|
131
131
|
flash[:success] = 'Password Updated'
|
|
132
132
|
redirect "#{settings.map_path}/auth/login"
|
|
133
133
|
else
|
|
134
134
|
broadcast(:identity_update_password_failed, target: self)
|
|
135
|
-
haml :'auth/reset_password', locals: { title: 'Reset your password', identity: identity }
|
|
135
|
+
haml :'auth/reset_password', locals: { title: 'Reset your password', identity: identity }, layout: :blank
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
|
|
@@ -141,7 +141,7 @@ module Ditty
|
|
|
141
141
|
authorize ::Ditty::User.new, :register
|
|
142
142
|
|
|
143
143
|
identity = Identity.new
|
|
144
|
-
haml :'auth/register', locals: { title: 'Register', identity: identity }
|
|
144
|
+
haml :'auth/register', locals: { title: 'Register', identity: identity }, layout: :blank
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
# Register Action
|
|
@@ -152,8 +152,9 @@ module Ditty
|
|
|
152
152
|
authorize user, :register
|
|
153
153
|
|
|
154
154
|
begin
|
|
155
|
+
identity.valid?
|
|
155
156
|
DB.transaction do
|
|
156
|
-
user.
|
|
157
|
+
user.save_changes
|
|
157
158
|
user.add_identity identity
|
|
158
159
|
broadcast(:user_register, target: self, values: { user: user })
|
|
159
160
|
flash[:info] = 'Successfully Registered. Please log in'
|
|
@@ -161,7 +162,7 @@ module Ditty
|
|
|
161
162
|
end
|
|
162
163
|
rescue Sequel::ValidationFailed
|
|
163
164
|
flash.now[:warning] = 'Could not complete the registration. Please try again.'
|
|
164
|
-
haml :'auth/register', locals: { identity: identity }
|
|
165
|
+
haml :'auth/register', locals: { identity: identity }, layout: :blank
|
|
165
166
|
end
|
|
166
167
|
end
|
|
167
168
|
|
|
@@ -172,7 +173,7 @@ module Ditty
|
|
|
172
173
|
|
|
173
174
|
halt 200 if request.xhr?
|
|
174
175
|
flash[:info] = 'Logged Out'
|
|
175
|
-
redirect(Ditty::Services::Settings[:logout_redirect_path] || "#{settings.map_path}/")
|
|
176
|
+
redirect(::Ditty::Services::Settings[:logout_redirect_path] || "#{settings.map_path}/")
|
|
176
177
|
end
|
|
177
178
|
|
|
178
179
|
# Unauthenticated
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/application_controller'
|
|
4
4
|
require 'ditty/helpers/component'
|
|
5
5
|
require 'ditty/helpers/response'
|
|
6
6
|
require 'sinatra/json'
|
|
7
7
|
|
|
8
8
|
module Ditty
|
|
9
|
-
class
|
|
9
|
+
class ComponentController < ApplicationController
|
|
10
10
|
helpers Helpers::Component, Helpers::Response
|
|
11
11
|
|
|
12
12
|
set base_path: nil
|
|
@@ -16,7 +16,12 @@ module Ditty
|
|
|
16
16
|
set heading: nil
|
|
17
17
|
|
|
18
18
|
def read(id)
|
|
19
|
-
dataset.
|
|
19
|
+
dataset.with_pk(id)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def read!(id)
|
|
23
|
+
halt 404 unless (entity = read(id))
|
|
24
|
+
entity
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def skip_verify!
|
|
@@ -25,7 +30,7 @@ module Ditty
|
|
|
25
30
|
|
|
26
31
|
def trigger(event, attribs = {})
|
|
27
32
|
attribs[:target] ||= self
|
|
28
|
-
send(event, attribs) if
|
|
33
|
+
send(event, attribs) if respond_to? event
|
|
29
34
|
broadcast(event, attribs)
|
|
30
35
|
end
|
|
31
36
|
|
|
@@ -58,8 +63,7 @@ module Ditty
|
|
|
58
63
|
get '/new/?' do
|
|
59
64
|
authorize settings.model_class, :create
|
|
60
65
|
|
|
61
|
-
entity = settings.model_class.new(
|
|
62
|
-
session[:redirect_to] = request.fullpath
|
|
66
|
+
entity = settings.model_class.new(permitted_parameters(settings.model_class, :create))
|
|
63
67
|
haml :"#{view_location}/new",
|
|
64
68
|
locals: { entity: entity, title: heading(:new) },
|
|
65
69
|
layout: layout
|
|
@@ -67,11 +71,11 @@ module Ditty
|
|
|
67
71
|
|
|
68
72
|
# Create
|
|
69
73
|
post '/' do
|
|
70
|
-
entity = settings.model_class.new(
|
|
74
|
+
entity = settings.model_class.new(permitted_parameters(settings.model_class, :create))
|
|
71
75
|
authorize entity, :create
|
|
72
76
|
|
|
73
77
|
entity.db.transaction do
|
|
74
|
-
entity.
|
|
78
|
+
entity.save_changes # Will trigger a Sequel::ValidationFailed exception if the model is incorrect
|
|
75
79
|
trigger :component_create, entity: entity
|
|
76
80
|
end
|
|
77
81
|
|
|
@@ -80,8 +84,7 @@ module Ditty
|
|
|
80
84
|
|
|
81
85
|
# Read
|
|
82
86
|
get '/:id/?' do |id|
|
|
83
|
-
entity = read(id)
|
|
84
|
-
halt 404 unless entity
|
|
87
|
+
entity = read!(id)
|
|
85
88
|
authorize entity, :read
|
|
86
89
|
|
|
87
90
|
trigger :component_read, entity: entity
|
|
@@ -90,10 +93,10 @@ module Ditty
|
|
|
90
93
|
|
|
91
94
|
# Update Form
|
|
92
95
|
get '/:id/edit/?' do |id|
|
|
93
|
-
entity = read(id)
|
|
94
|
-
halt 404 unless entity
|
|
96
|
+
entity = read!(id)
|
|
95
97
|
authorize entity, :update
|
|
96
98
|
|
|
99
|
+
flash[:redirect_to] = "#{base_path}/#{entity.display_id}"
|
|
97
100
|
haml :"#{view_location}/edit",
|
|
98
101
|
locals: { entity: entity, title: heading(:edit) },
|
|
99
102
|
layout: layout
|
|
@@ -101,13 +104,12 @@ module Ditty
|
|
|
101
104
|
|
|
102
105
|
# Update
|
|
103
106
|
put '/:id/?' do |id|
|
|
104
|
-
entity = read(id)
|
|
105
|
-
halt 404 unless entity
|
|
107
|
+
entity = read!(id)
|
|
106
108
|
authorize entity, :update
|
|
107
109
|
|
|
108
110
|
entity.db.transaction do
|
|
109
|
-
entity.set(
|
|
110
|
-
entity.
|
|
111
|
+
entity.set(permitted_parameters(settings.model_class, :update))
|
|
112
|
+
entity.save_changes # Will trigger a Sequel::ValidationFailed exception if the model is incorrect
|
|
111
113
|
trigger :component_update, entity: entity
|
|
112
114
|
end
|
|
113
115
|
|
|
@@ -115,8 +117,7 @@ module Ditty
|
|
|
115
117
|
end
|
|
116
118
|
|
|
117
119
|
delete '/:id/?' do |id|
|
|
118
|
-
entity = read(id)
|
|
119
|
-
halt 404 unless entity
|
|
120
|
+
entity = read!(id)
|
|
120
121
|
authorize entity, :delete
|
|
121
122
|
|
|
122
123
|
entity.db.transaction do
|
|
@@ -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
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'ditty/controllers/
|
|
3
|
+
require 'ditty/controllers/component_controller'
|
|
4
4
|
require 'ditty/models/user_login_trait'
|
|
5
5
|
require 'ditty/policies/user_login_trait_policy'
|
|
6
6
|
|
|
7
7
|
module Ditty
|
|
8
|
-
class
|
|
8
|
+
class UserLoginTraitsController < ::Ditty::ComponentController
|
|
9
9
|
SEARCHABLE = %i[platform device browser ip_address].freeze
|
|
10
10
|
FILTERS = [
|
|
11
11
|
{ name: :user, field: 'user.email' }
|
|
12
12
|
].freeze
|
|
13
13
|
|
|
14
|
-
set base_path: 'login-traits'
|
|
14
|
+
set base_path: '/login-traits'
|
|
15
15
|
set model_class: UserLoginTrait
|
|
16
|
+
set heading: 'Login'
|
|
16
17
|
# set track_actions: true
|
|
17
18
|
end
|
|
18
19
|
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|
|
|
@@ -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,9 @@ 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? && identity.
|
|
99
|
+
if identity.valid? && identity.save_changes
|
|
100
100
|
broadcast(:identity_update_password, target: self)
|
|
101
101
|
flash[:success] = 'Password Updated'
|
|
102
102
|
redirect back
|
|
@@ -129,6 +129,7 @@ module Ditty
|
|
|
129
129
|
halt 404 unless entity
|
|
130
130
|
authorize entity, :read
|
|
131
131
|
|
|
132
|
+
flash[:redirect_to] = request.path
|
|
132
133
|
haml :"#{view_location}/profile", locals: { entity: entity, identity: entity.identity.first, title: 'My Account' }
|
|
133
134
|
end
|
|
134
135
|
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,7 +18,7 @@ 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')
|
|
@@ -26,6 +26,7 @@ elsif ENV['DATABASE_URL'].blank? == false
|
|
|
26
26
|
Sequel::Model.plugin :validation_helpers
|
|
27
27
|
Sequel::Model.plugin :update_or_create
|
|
28
28
|
Sequel::Model.plugin :timestamps, update_on_create: true
|
|
29
|
+
Sequel::Model.plugin :auto_validations
|
|
29
30
|
else
|
|
30
|
-
Ditty::Services::Logger.
|
|
31
|
+
::Ditty::Services::Logger.error 'No database connection set up'
|
|
31
32
|
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
|
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_controller
|
|
37
|
+
filename = File.join("lib/#{folder}/controllers", "#{controller_name.underscore}.rb")
|
|
38
|
+
template '../templates/controller.rb.erb', filename
|
|
39
|
+
# TODO: Insert the route into the component file
|
|
40
|
+
# insert_into_file 'config.ru', "use #{class_name}\n", after: 'run ApplicationController\n'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_policy
|
|
44
|
+
filename = File.join("lib/#{folder}/policies", "#{policy_name.underscore}.rb")
|
|
45
|
+
template '../templates/policy.rb.erb', filename
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def create_type
|
|
49
|
+
filename = File.join("lib/#{folder}/types", "#{model_name.underscore}_type.rb")
|
|
50
|
+
template '../templates/type.rb.erb', filename
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_views
|
|
54
|
+
return unless options[:views]
|
|
55
|
+
|
|
56
|
+
directory '../templates/views', views_folder
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def meta_columns
|
|
62
|
+
%i[id guid slug created_at updated_at]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def columns
|
|
66
|
+
require "#{folder}/models/#{model_name.underscore}"
|
|
67
|
+
name.constantize.columns
|
|
68
|
+
rescue StandardError
|
|
69
|
+
[]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def schema
|
|
73
|
+
require "#{folder}/models/#{model_name.underscore}"
|
|
74
|
+
name.constantize.db_schema
|
|
75
|
+
rescue StandardError
|
|
76
|
+
[]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def many_to_ones
|
|
80
|
+
DB.foreign_key_list(model_name.underscore.pluralize)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def name_column(table)
|
|
84
|
+
candidates = DB.schema(table.to_sym).to_h.keys - DB.foreign_key_list(table.to_sym).map { |e| e[:columns] }.flatten
|
|
85
|
+
(candidates - meta_columns).first
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def graphql_types
|
|
89
|
+
@graphql_types ||= Hash.new('String').merge(
|
|
90
|
+
integer: 'Integer',
|
|
91
|
+
boolean: 'Boolean',
|
|
92
|
+
datetime: 'GraphQL::Types::ISO8601DateTime'
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def input_types
|
|
97
|
+
@input_types ||= Hash.new('text').merge(
|
|
98
|
+
integer: 'number',
|
|
99
|
+
datetime: 'date'
|
|
100
|
+
)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|