ditty 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|