ditty 0.9.1 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.test +2 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +23 -4
- data/.travis.yml +2 -7
- data/Gemfile.ci +0 -15
- data/ditty.gemspec +19 -15
- data/lib/ditty.rb +2 -2
- data/lib/ditty/cli.rb +5 -0
- data/lib/ditty/components/ditty.rb +4 -7
- data/lib/ditty/controllers/application_controller.rb +6 -5
- data/lib/ditty/controllers/audit_logs_controller.rb +2 -0
- data/lib/ditty/controllers/auth_controller.rb +5 -2
- data/lib/ditty/controllers/component_controller.rb +3 -3
- data/lib/ditty/controllers/user_login_traits_controller.rb +28 -1
- data/lib/ditty/controllers/users_controller.rb +3 -2
- data/lib/ditty/db.rb +4 -3
- data/lib/ditty/emails/base.rb +32 -30
- data/lib/ditty/generators/crud_generator.rb +51 -41
- data/lib/ditty/generators/project_generator.rb +1 -0
- data/lib/ditty/helpers/pundit.rb +4 -4
- data/lib/ditty/helpers/response.rb +6 -11
- data/lib/ditty/helpers/views.rb +21 -3
- data/lib/ditty/listener.rb +1 -1
- data/lib/ditty/models/base.rb +5 -0
- data/lib/ditty/models/identity.rb +7 -7
- data/lib/ditty/models/user.rb +9 -1
- data/lib/ditty/policies/user_policy.rb +1 -1
- data/lib/ditty/services/authentication.rb +19 -9
- data/lib/ditty/services/email.rb +13 -13
- 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 +2 -1
- data/lib/ditty/templates/application.rb +1 -1
- data/lib/ditty/templates/config.ru +2 -2
- data/lib/ditty/templates/controller.rb.erb +7 -1
- data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
- data/{public → lib/ditty/templates/public}/css/styles.css +0 -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/{public → lib/ditty/templates/public}/js/scripts.js +0 -0
- data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
- data/lib/ditty/templates/settings.yml.erb +1 -0
- data/lib/ditty/templates/spec_helper.rb +1 -1
- data/lib/ditty/templates/views/display.haml.tt +1 -1
- data/lib/ditty/templates/views/edit.haml.tt +1 -1
- data/lib/ditty/templates/views/index.haml.tt +1 -1
- data/lib/ditty/templates/views/new.haml.tt +1 -1
- data/lib/ditty/version.rb +1 -1
- data/spec/ditty/api_spec.rb +1 -1
- data/spec/ditty/emails/base_spec.rb +3 -3
- data/spec/ditty/emails/forgot_password_spec.rb +3 -2
- data/spec/ditty/models/user_spec.rb +3 -3
- data/spec/ditty/services/logger_spec.rb +7 -6
- data/spec/ditty/services/settings_spec.rb +2 -2
- data/spec/factories.rb +4 -4
- data/spec/spec_helper.rb +5 -1
- data/views/403.haml +1 -1
- data/views/500.haml +11 -0
- data/views/audit_logs/index.haml +12 -11
- data/views/auth/forgot_password.haml +29 -24
- data/views/auth/ldap.haml +1 -1
- data/views/auth/login.haml +3 -2
- data/views/auth/register.haml +3 -2
- data/views/auth/reset_password.haml +36 -19
- data/views/blank.haml +1 -0
- data/views/embedded.haml +17 -11
- data/views/layout.haml +16 -8
- data/views/partials/actions.haml +15 -14
- data/views/partials/filter_control.haml +1 -1
- data/views/partials/footer.haml +10 -2
- data/views/partials/form_tag.haml +1 -1
- data/views/partials/navitems.haml +25 -27
- data/views/partials/pager.haml +44 -25
- data/views/partials/search.haml +14 -9
- data/views/partials/sidebar.haml +2 -2
- data/views/partials/sort_ui.haml +2 -0
- data/views/partials/timespan_selector.haml +64 -0
- data/views/partials/topbar.haml +0 -15
- data/views/partials/user_associations.haml +32 -0
- data/views/quick_start.haml +23 -0
- data/views/roles/display.haml +3 -3
- data/views/roles/edit.haml +1 -1
- data/views/roles/index.haml +2 -2
- data/views/roles/new.haml +1 -1
- data/views/user_login_traits/display.haml +1 -1
- data/views/user_login_traits/edit.haml +1 -1
- data/views/user_login_traits/index.haml +23 -25
- data/views/user_login_traits/new.haml +1 -1
- data/views/users/display.haml +5 -5
- data/views/users/edit.haml +1 -1
- data/views/users/index.haml +5 -5
- data/views/users/login_traits.haml +2 -2
- data/views/users/new.haml +1 -1
- data/views/users/profile.haml +4 -4
- data/views/users/user.haml +1 -1
- metadata +116 -54
@@ -31,6 +31,8 @@ module Ditty
|
|
31
31
|
def create_model
|
32
32
|
filename = File.join("lib/#{folder}/models", "#{model_name.underscore}.rb")
|
33
33
|
template '../templates/model.rb.erb', filename
|
34
|
+
rescue StandardError => e
|
35
|
+
puts "Could not generate model for #{model_name}: #{e.message}"
|
34
36
|
end
|
35
37
|
|
36
38
|
def create_controller
|
@@ -38,16 +40,22 @@ module Ditty
|
|
38
40
|
template '../templates/controller.rb.erb', filename
|
39
41
|
# TODO: Insert the route into the component file
|
40
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}"
|
41
45
|
end
|
42
46
|
|
43
47
|
def create_policy
|
44
48
|
filename = File.join("lib/#{folder}/policies", "#{policy_name.underscore}.rb")
|
45
49
|
template '../templates/policy.rb.erb', filename
|
50
|
+
rescue StandardError => e
|
51
|
+
puts "Could not generate policy for #{model_name}: #{e.message}"
|
46
52
|
end
|
47
53
|
|
48
54
|
def create_type
|
49
55
|
filename = File.join("lib/#{folder}/types", "#{model_name.underscore}_type.rb")
|
50
56
|
template '../templates/type.rb.erb', filename
|
57
|
+
rescue StandardError => e
|
58
|
+
puts "Could not generate type for #{model_name}: #{e.message}"
|
51
59
|
end
|
52
60
|
|
53
61
|
def create_views
|
@@ -58,47 +66,49 @@ module Ditty
|
|
58
66
|
|
59
67
|
private
|
60
68
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
102
112
|
end
|
103
113
|
end
|
104
114
|
end
|
data/lib/ditty/helpers/pundit.rb
CHANGED
@@ -16,10 +16,10 @@ module Ditty
|
|
16
16
|
policy = policy(record)
|
17
17
|
action ||= record.new? ? :create : :update
|
18
18
|
method_name = if policy.respond_to?("permitted_attributes_for_#{action}")
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
"permitted_attributes_for_#{action}"
|
20
|
+
else
|
21
|
+
'permitted_attributes'
|
22
|
+
end
|
23
23
|
policy.public_send(method_name)
|
24
24
|
end
|
25
25
|
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'csv'
|
4
4
|
|
5
|
-
require 'csv'
|
6
|
-
|
7
5
|
module Ditty
|
8
6
|
module Helpers
|
9
7
|
module Response
|
@@ -27,6 +25,7 @@ module Ditty
|
|
27
25
|
)
|
28
26
|
end
|
29
27
|
format.csv do
|
28
|
+
attachment "#{base_path}.csv"
|
30
29
|
CSV.generate do |csv|
|
31
30
|
csv << result.first.for_csv.keys
|
32
31
|
result.all.each do |r|
|
@@ -41,7 +40,7 @@ module Ditty
|
|
41
40
|
respond_to do |format|
|
42
41
|
format.html do
|
43
42
|
flash[:success] = "#{heading} Created"
|
44
|
-
redirect with_layout(flash[:redirect_to] || "#{base_path}/#{entity.display_id}")
|
43
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || "#{base_path}/#{entity.display_id}")
|
45
44
|
end
|
46
45
|
format.json do
|
47
46
|
content_type :json
|
@@ -62,6 +61,8 @@ module Ditty
|
|
62
61
|
respond_to do |format|
|
63
62
|
format.html do
|
64
63
|
title = heading(:read) + (entity.respond_to?(:name) ? ": #{entity.name}" : '')
|
64
|
+
last_modified entity.updated_at if entity.respond_to?(:updated_at)
|
65
|
+
etag entity.etag if entity.respond_to?(:etag)
|
65
66
|
haml :"#{view_location}/display",
|
66
67
|
locals: { entity: entity, title: title, actions: actions },
|
67
68
|
layout: layout
|
@@ -76,12 +77,6 @@ module Ditty
|
|
76
77
|
csv << entity.for_csv.values
|
77
78
|
end
|
78
79
|
end
|
79
|
-
format.csv do
|
80
|
-
CSV.generate do |csv|
|
81
|
-
csv << entity.for_csv.keys
|
82
|
-
csv << entity.for_csv.values
|
83
|
-
end
|
84
|
-
end
|
85
80
|
end
|
86
81
|
end
|
87
82
|
|
@@ -90,7 +85,7 @@ module Ditty
|
|
90
85
|
format.html do
|
91
86
|
# TODO: Ability to customize the return path and message?
|
92
87
|
flash[:success] = "#{heading} Updated"
|
93
|
-
redirect with_layout(
|
88
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || "#{base_path}/#{entity.display_id}")
|
94
89
|
end
|
95
90
|
format.json do
|
96
91
|
content_type :json
|
@@ -103,7 +98,7 @@ module Ditty
|
|
103
98
|
respond_to do |format|
|
104
99
|
format.html do
|
105
100
|
flash[:success] = "#{heading} Deleted"
|
106
|
-
redirect with_layout(flash[:redirect_to] || back || base_path)
|
101
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || back || base_path)
|
107
102
|
end
|
108
103
|
format.json do
|
109
104
|
content_type :json
|
data/lib/ditty/helpers/views.rb
CHANGED
@@ -62,13 +62,13 @@ module Ditty
|
|
62
62
|
messages = flash(key).collect do |message|
|
63
63
|
" <div class='alert alert-#{message[0]} alert-dismissable' role='alert'>#{message[1]}</div>\n"
|
64
64
|
end
|
65
|
-
"<div id='#{id}'>\n
|
65
|
+
"<div id='#{id}'>\n#{messages.join}</div>"
|
66
66
|
end
|
67
67
|
|
68
68
|
def query_string(add = {})
|
69
69
|
qs = params.clone.merge(add)
|
70
70
|
qs.delete('captures')
|
71
|
-
Rack::Utils.build_query
|
71
|
+
Rack::Utils.build_query(qs.delete_if { |_k, v| v == '' })
|
72
72
|
end
|
73
73
|
|
74
74
|
def delete_form(entity, label = 'Delete')
|
@@ -94,7 +94,7 @@ module Ditty
|
|
94
94
|
def form_tag(url, options = {}, &block)
|
95
95
|
options[:form_verb] ||= :post
|
96
96
|
options[:attributes] ||= {}
|
97
|
-
options[:attributes] = {
|
97
|
+
options[:attributes] = { class: 'form-horizontal' }.merge options[:attributes]
|
98
98
|
options[:url] = options[:form_verb].to_sym == :get ? url : with_layout(url)
|
99
99
|
haml :'partials/form_tag', locals: options.merge(block: block)
|
100
100
|
end
|
@@ -138,6 +138,24 @@ module Ditty
|
|
138
138
|
haml_tag :a, name, html_options
|
139
139
|
end
|
140
140
|
end
|
141
|
+
|
142
|
+
def sort_ui(field)
|
143
|
+
haml :'partials/sort_ui', locals: { field: field }
|
144
|
+
end
|
145
|
+
|
146
|
+
def sort_query(field)
|
147
|
+
query_string(
|
148
|
+
order: params[:sort] == field.to_s && params[:order] == 'asc' ? 'desc' : 'asc',
|
149
|
+
sort: field,
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
def sort_icon(field)
|
154
|
+
return 'fa-sort' unless params[:sort] == field.to_s
|
155
|
+
return 'fa-sort-up' if params[:order] == 'asc'
|
156
|
+
|
157
|
+
'fa-sort-down'
|
158
|
+
end
|
141
159
|
end
|
142
160
|
end
|
143
161
|
end
|
data/lib/ditty/listener.rb
CHANGED
@@ -66,7 +66,7 @@ module Ditty
|
|
66
66
|
def action_from(target, method)
|
67
67
|
return method unless method.to_s.start_with? 'component_'
|
68
68
|
|
69
|
-
target.class.to_s.demodulize.underscore
|
69
|
+
"#{target.class.to_s.demodulize.underscore}_#{method.to_s.gsub(/^component_/, '')}"
|
70
70
|
end
|
71
71
|
|
72
72
|
def log_action(values)
|
data/lib/ditty/models/base.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'digest/sha2'
|
3
4
|
require 'sequel'
|
4
5
|
|
5
6
|
module Ditty
|
@@ -12,6 +13,10 @@ module Ditty
|
|
12
13
|
self[:slug] || self[:guid] || self[:id]
|
13
14
|
end
|
14
15
|
|
16
|
+
def etag
|
17
|
+
Digest::SHA2.hexdigest values.to_json
|
18
|
+
end
|
19
|
+
|
15
20
|
alias for_csv for_json
|
16
21
|
end
|
17
22
|
end
|
@@ -55,7 +55,7 @@ module Ditty
|
|
55
55
|
# 1 Special Character
|
56
56
|
# 1 Number
|
57
57
|
# At least 8 characters
|
58
|
-
%r[\A(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#&$*)(}{%^=_+|\\:";'
|
58
|
+
%r[\A(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#&$*)(}{%^=_+|\\:";'<>,.\-/?\[\]])(?=.*[0-9]).{8,}\Z],
|
59
59
|
:password,
|
60
60
|
message: 'is not strong enough'
|
61
61
|
)
|
@@ -72,12 +72,12 @@ module Ditty
|
|
72
72
|
|
73
73
|
private
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
def encrypt_password
|
76
|
+
self.crypted_password = ::BCrypt::Password.create(password)
|
77
|
+
end
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
def password_required
|
80
|
+
crypted_password.blank? || !password.blank?
|
81
|
+
end
|
82
82
|
end
|
83
83
|
end
|
data/lib/ditty/models/user.rb
CHANGED
@@ -40,7 +40,9 @@ module Ditty
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def respond_to_missing?(name, _include_private = false)
|
43
|
-
name[-1] == '?'
|
43
|
+
return true if name[-1] == '?'
|
44
|
+
|
45
|
+
super
|
44
46
|
end
|
45
47
|
|
46
48
|
def gravatar
|
@@ -57,6 +59,12 @@ module Ditty
|
|
57
59
|
validates_format(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :email)
|
58
60
|
end
|
59
61
|
|
62
|
+
def before_save
|
63
|
+
super
|
64
|
+
self.name = nil if name.blank?
|
65
|
+
self.surname = nil if surname.blank?
|
66
|
+
end
|
67
|
+
|
60
68
|
# Add the basic roles and identity
|
61
69
|
def after_create
|
62
70
|
super
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'ditty/controllers/application_controller'
|
4
4
|
require 'ditty/services/settings'
|
5
5
|
require 'ditty/services/logger'
|
6
|
-
require 'backports/2.4.0/hash/compact'
|
7
6
|
|
8
7
|
require 'omniauth'
|
9
8
|
OmniAuth.config.logger = ::Ditty::Services::Logger
|
@@ -23,26 +22,36 @@ module Ditty
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def providers
|
26
|
-
config.compact.keys
|
25
|
+
config.compact.keys.select { |e| config[e][:available] && config[e][:enabled] != false }
|
27
26
|
end
|
28
27
|
|
29
28
|
def setup
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
require
|
29
|
+
config.compact.each_key do |provider|
|
30
|
+
::Ditty::Services::Logger.debug "Loading authentication provider #{provider}"
|
31
|
+
req = if config.dig(provider, :require)
|
32
|
+
[config[provider][:require]]
|
33
|
+
else
|
34
|
+
["omniauth/#{provider}", "omniauth-#{provider}"]
|
35
|
+
end
|
36
|
+
req.find do |e|
|
37
|
+
require e
|
38
|
+
config[provider][:available] = true
|
39
|
+
true
|
34
40
|
rescue LoadError
|
35
|
-
|
41
|
+
::Ditty::Services::Logger.warn "Could not load authentication provider #{provider} using #{e}"
|
42
|
+
config[provider][:available] = false
|
43
|
+
false
|
36
44
|
end
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
40
48
|
def config
|
41
|
-
default.merge
|
49
|
+
@config ||= default.merge(::Ditty::Services::Settings.values(:authentication) || {})
|
42
50
|
end
|
43
51
|
|
44
52
|
def provides?(provider)
|
45
|
-
|
53
|
+
provider = provider.to_sym
|
54
|
+
providers.include?(provider) && config[provider][:available] && config.dig(provider, :enabled) != false
|
46
55
|
end
|
47
56
|
|
48
57
|
def default
|
@@ -50,6 +59,7 @@ module Ditty
|
|
50
59
|
require 'ditty/controllers/auth_controller'
|
51
60
|
{
|
52
61
|
identity: {
|
62
|
+
available: true,
|
53
63
|
arguments: [
|
54
64
|
{
|
55
65
|
fields: [:username],
|
data/lib/ditty/services/email.rb
CHANGED
@@ -34,21 +34,21 @@ module Ditty
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def config
|
38
|
+
@config ||= default.merge ::Ditty::Services::Settings.values(:email) || {}
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def default
|
42
|
+
{
|
43
|
+
delivery_method: :logger,
|
44
|
+
logger: ::Ditty::Services::Logger
|
45
|
+
}
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
def from_symbol(email, options)
|
49
|
+
require "ditty/emails/#{email}"
|
50
|
+
constantize("Ditty::Emails::#{classify(email)}").new(options)
|
51
|
+
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|