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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'thor/group'
|
|
4
|
+
require 'active_support/inflector'
|
|
5
|
+
|
|
6
|
+
module Ditty
|
|
7
|
+
module Generators
|
|
8
|
+
class ProjectGenerator < Thor::Group
|
|
9
|
+
include Thor::Actions
|
|
10
|
+
|
|
11
|
+
attr_reader :name, :namespace, :folder
|
|
12
|
+
|
|
13
|
+
desc 'Initialize a new Ditty project in the current folder'
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@name = File.basename(Dir.getwd)
|
|
17
|
+
@folder = @name.underscore
|
|
18
|
+
@namespace = folder.classify
|
|
19
|
+
@name = @name.titleize
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.source_root
|
|
23
|
+
File.expand_path('../templates', __dir__)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def create_startup_files
|
|
27
|
+
directory 'logs'
|
|
28
|
+
directory 'pids'
|
|
29
|
+
directory 'public'
|
|
30
|
+
directory '../../../views', 'views'
|
|
31
|
+
copy_file '.gitignore', './.gitignore'
|
|
32
|
+
copy_file 'env.example', './.env'
|
|
33
|
+
copy_file '.rubocop.yml', './.rubocop.yml'
|
|
34
|
+
copy_file '.rspec', './.rspec'
|
|
35
|
+
|
|
36
|
+
template 'lib/project.rb.erb', "lib/#{folder}.rb"
|
|
37
|
+
|
|
38
|
+
copy_file 'application.rb', './application.rb'
|
|
39
|
+
copy_file 'config.ru', './config.ru'
|
|
40
|
+
copy_file 'Rakefile', './Rakefile'
|
|
41
|
+
copy_file 'sidekiq.rb', './config/sidekiq.rb'
|
|
42
|
+
copy_file 'sidekiq.yml', './config/sidekiq.yml'
|
|
43
|
+
|
|
44
|
+
copy_file 'spec_helper.rb', './specs/spec_helper.rb'
|
|
45
|
+
copy_file '../../../spec/support/api_shared_examples.rb', './specs/support/api_shared_examples.rb'
|
|
46
|
+
copy_file '../../../spec/support/crud_shared_examples.rb', './specs/support/crud_shared_examples.rb'
|
|
47
|
+
|
|
48
|
+
template 'settings.yml.erb', './config/settings.yml'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -33,11 +33,12 @@ module Ditty
|
|
|
33
33
|
param :q, String
|
|
34
34
|
param :page, Integer, min: 1, default: 1
|
|
35
35
|
param :sort, String
|
|
36
|
-
param :order, String, in: %w[asc desc], transform: :downcase
|
|
36
|
+
param :order, String, in: %w[asc desc], transform: :downcase
|
|
37
37
|
# TODO: Can we dynamically validate the search / filter fields?
|
|
38
38
|
|
|
39
39
|
ds = dataset
|
|
40
40
|
ds = ds.dataset if ds.respond_to?(:dataset)
|
|
41
|
+
params[:order] ||= 'asc' if params[:sort]
|
|
41
42
|
return ds if params[:count] == 'all'
|
|
42
43
|
|
|
43
44
|
params[:count] = check_count
|
data/lib/ditty/helpers/pundit.rb
CHANGED
|
@@ -12,23 +12,39 @@ module Ditty
|
|
|
12
12
|
super
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def permitted_attributes(record, action)
|
|
16
|
-
param_key = PolicyFinder.new(record).param_key
|
|
15
|
+
def permitted_attributes(record, action = nil)
|
|
17
16
|
policy = policy(record)
|
|
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
|
+
policy.public_send(method_name)
|
|
24
|
+
end
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
def permitted_parameters(record, action = nil)
|
|
27
|
+
param_key = PolicyFinder.new(record).param_key
|
|
28
|
+
policy_fields = permitted_attributes(record, action)
|
|
25
29
|
request.params.fetch(param_key, {}).select do |key, _value|
|
|
26
30
|
policy_fields.include? key.to_sym
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
|
|
34
|
+
def permitted_response_attributes(record, method = :values)
|
|
35
|
+
policy = policy(record)
|
|
36
|
+
response = record.send(method)
|
|
37
|
+
|
|
38
|
+
return response unless policy.respond_to? :response_attributes
|
|
39
|
+
|
|
40
|
+
policy_fields = policy.response_attributes
|
|
41
|
+
response.select do |key, _value|
|
|
42
|
+
policy_fields.include? key.to_sym
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
30
46
|
def pundit_user
|
|
31
|
-
current_user
|
|
47
|
+
current_user unless current_user&.anonymous?
|
|
32
48
|
end
|
|
33
49
|
end
|
|
34
50
|
end
|
|
@@ -5,12 +5,12 @@ require 'csv'
|
|
|
5
5
|
module Ditty
|
|
6
6
|
module Helpers
|
|
7
7
|
module Response
|
|
8
|
-
def list_response(result)
|
|
8
|
+
def list_response(result, view: 'index')
|
|
9
9
|
respond_to do |format|
|
|
10
10
|
format.html do
|
|
11
11
|
actions = {}
|
|
12
12
|
actions["#{base_path}/new"] = "New #{heading}" if policy(settings.model_class).create?
|
|
13
|
-
haml :"#{view_location}
|
|
13
|
+
haml :"#{view_location}/#{view}",
|
|
14
14
|
locals: { list: result, title: heading(:list), actions: actions },
|
|
15
15
|
layout: layout
|
|
16
16
|
end
|
|
@@ -18,13 +18,14 @@ module Ditty
|
|
|
18
18
|
# TODO: Add links defined by actions (New #{heading})
|
|
19
19
|
total = result.respond_to?(:pagination_record_count) ? result.pagination_record_count : result.count
|
|
20
20
|
json(
|
|
21
|
-
'items' => result.all.map(
|
|
21
|
+
'items' => result.all.map { |e| permitted_response_attributes(e, :for_json) },
|
|
22
22
|
'page' => (params['page'] || 1).to_i,
|
|
23
23
|
'count' => result.count,
|
|
24
24
|
'total' => total
|
|
25
25
|
)
|
|
26
26
|
end
|
|
27
27
|
format.csv do
|
|
28
|
+
attachment "#{base_path}.csv"
|
|
28
29
|
CSV.generate do |csv|
|
|
29
30
|
csv << result.first.for_csv.keys
|
|
30
31
|
result.all.each do |r|
|
|
@@ -39,18 +40,18 @@ module Ditty
|
|
|
39
40
|
respond_to do |format|
|
|
40
41
|
format.html do
|
|
41
42
|
flash[:success] = "#{heading} Created"
|
|
42
|
-
redirect with_layout("#{base_path}/#{entity.
|
|
43
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || "#{base_path}/#{entity.display_id}")
|
|
43
44
|
end
|
|
44
45
|
format.json do
|
|
45
46
|
content_type :json
|
|
46
|
-
redirect "#{base_path}/#{entity.
|
|
47
|
+
redirect "#{base_path}/#{entity.display_id}", 201
|
|
47
48
|
end
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def actions(entity = nil)
|
|
52
53
|
actions = {}
|
|
53
|
-
actions["#{base_path}/#{entity.
|
|
54
|
+
actions["#{base_path}/#{entity.display_id}/edit"] = "Edit #{heading}" if entity && policy(entity).update?
|
|
54
55
|
actions["#{base_path}/new"] = "New #{heading}" if policy(settings.model_class).create?
|
|
55
56
|
actions
|
|
56
57
|
end
|
|
@@ -60,13 +61,15 @@ module Ditty
|
|
|
60
61
|
respond_to do |format|
|
|
61
62
|
format.html do
|
|
62
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)
|
|
63
66
|
haml :"#{view_location}/display",
|
|
64
67
|
locals: { entity: entity, title: title, actions: actions },
|
|
65
68
|
layout: layout
|
|
66
69
|
end
|
|
67
70
|
format.json do
|
|
68
71
|
# TODO: Add links defined by actions (Edit #{heading})
|
|
69
|
-
json entity
|
|
72
|
+
json permitted_response_attributes(entity, :for_json)
|
|
70
73
|
end
|
|
71
74
|
format.csv do
|
|
72
75
|
CSV.generate do |csv|
|
|
@@ -82,11 +85,11 @@ module Ditty
|
|
|
82
85
|
format.html do
|
|
83
86
|
# TODO: Ability to customize the return path and message?
|
|
84
87
|
flash[:success] = "#{heading} Updated"
|
|
85
|
-
redirect with_layout("#{base_path}/#{entity.
|
|
88
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || "#{base_path}/#{entity.display_id}")
|
|
86
89
|
end
|
|
87
90
|
format.json do
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
content_type :json
|
|
92
|
+
redirect "#{base_path}/#{entity.display_id}", 200, json(entity.for_json)
|
|
90
93
|
end
|
|
91
94
|
end
|
|
92
95
|
end
|
|
@@ -95,12 +98,11 @@ module Ditty
|
|
|
95
98
|
respond_to do |format|
|
|
96
99
|
format.html do
|
|
97
100
|
flash[:success] = "#{heading} Deleted"
|
|
98
|
-
redirect with_layout(base_path
|
|
101
|
+
redirect with_layout(params[:redirect_to] || flash[:redirect_to] || back || base_path)
|
|
99
102
|
end
|
|
100
103
|
format.json do
|
|
101
104
|
content_type :json
|
|
102
|
-
|
|
103
|
-
status 204
|
|
105
|
+
redirect base_path.to_s, 204
|
|
104
106
|
end
|
|
105
107
|
end
|
|
106
108
|
end
|
data/lib/ditty/helpers/views.rb
CHANGED
|
@@ -24,9 +24,11 @@ module Ditty
|
|
|
24
24
|
def form_control(name, model, opts = {})
|
|
25
25
|
label = opts.delete(:label) || name.to_s.titlecase
|
|
26
26
|
klass = opts.delete(:class) || 'form-control' unless opts[:type] == 'file'
|
|
27
|
+
klass = "#{klass} is-invalid" if model.errors[name]
|
|
27
28
|
group = opts.delete(:group) || model.class.to_s.demodulize.underscore
|
|
28
29
|
field = opts.delete(:field) || name
|
|
29
30
|
default = opts.delete(:default) || nil
|
|
31
|
+
help_text = opts.delete(:help_text) || nil
|
|
30
32
|
|
|
31
33
|
attributes = { type: 'text', id: name, name: "#{group}[#{name}]", class: klass }.merge(opts)
|
|
32
34
|
haml :'partials/form_control', locals: {
|
|
@@ -36,7 +38,8 @@ module Ditty
|
|
|
36
38
|
name: name,
|
|
37
39
|
group: group,
|
|
38
40
|
field: field,
|
|
39
|
-
default: default
|
|
41
|
+
default: default,
|
|
42
|
+
help_text: help_text
|
|
40
43
|
}
|
|
41
44
|
end
|
|
42
45
|
|
|
@@ -47,7 +50,8 @@ module Ditty
|
|
|
47
50
|
haml :'partials/filter_control', locals: {
|
|
48
51
|
name: filter[:name],
|
|
49
52
|
label: opts[:label] || filter[:name].to_s.titlecase,
|
|
50
|
-
options: send(meth)
|
|
53
|
+
options: send(meth),
|
|
54
|
+
total_filters: opts[:filters]
|
|
51
55
|
}
|
|
52
56
|
end
|
|
53
57
|
|
|
@@ -58,13 +62,13 @@ module Ditty
|
|
|
58
62
|
messages = flash(key).collect do |message|
|
|
59
63
|
" <div class='alert alert-#{message[0]} alert-dismissable' role='alert'>#{message[1]}</div>\n"
|
|
60
64
|
end
|
|
61
|
-
"<div id='#{id}'>\n
|
|
65
|
+
"<div id='#{id}'>\n#{messages.join}</div>"
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def query_string(add = {})
|
|
65
69
|
qs = params.clone.merge(add)
|
|
66
70
|
qs.delete('captures')
|
|
67
|
-
Rack::Utils.build_query
|
|
71
|
+
Rack::Utils.build_query(qs.delete_if { |_k, v| v == '' })
|
|
68
72
|
end
|
|
69
73
|
|
|
70
74
|
def delete_form(entity, label = 'Delete')
|
|
@@ -90,7 +94,7 @@ module Ditty
|
|
|
90
94
|
def form_tag(url, options = {}, &block)
|
|
91
95
|
options[:form_verb] ||= :post
|
|
92
96
|
options[:attributes] ||= {}
|
|
93
|
-
options[:attributes] = {
|
|
97
|
+
options[:attributes] = { class: 'form-horizontal' }.merge options[:attributes]
|
|
94
98
|
options[:url] = options[:form_verb].to_sym == :get ? url : with_layout(url)
|
|
95
99
|
haml :'partials/form_tag', locals: options.merge(block: block)
|
|
96
100
|
end
|
|
@@ -98,7 +102,7 @@ module Ditty
|
|
|
98
102
|
def pagination(list, base_path, qp = {})
|
|
99
103
|
return unless list.respond_to?(:pagination_record_count) || list.respond_to?(:total_entries)
|
|
100
104
|
|
|
101
|
-
list = Ditty::Services::PaginationWrapper.new(list)
|
|
105
|
+
list = ::Ditty::Services::PaginationWrapper.new(list)
|
|
102
106
|
locals = {
|
|
103
107
|
first_link: "#{base_path}?" + query_string(qp.merge(page: 1)),
|
|
104
108
|
next_link: list.last_page? ? '#' : "#{base_path}?" + query_string(qp.merge(page: list.next_page)),
|
|
@@ -134,6 +138,24 @@ module Ditty
|
|
|
134
138
|
haml_tag :a, name, html_options
|
|
135
139
|
end
|
|
136
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
|
|
137
159
|
end
|
|
138
160
|
end
|
|
139
161
|
end
|
data/lib/ditty/listener.rb
CHANGED
|
@@ -17,7 +17,9 @@ module Ditty
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def method_missing(method, *args)
|
|
20
|
-
|
|
20
|
+
unless args[0].is_a?(Hash) && args[0][:target].is_a?(Sinatra::Base) && args[0][:target].settings.track_actions
|
|
21
|
+
return
|
|
22
|
+
end
|
|
21
23
|
|
|
22
24
|
log_action(
|
|
23
25
|
user_traits(args[0][:target]).merge(
|
|
@@ -64,12 +66,12 @@ module Ditty
|
|
|
64
66
|
def action_from(target, method)
|
|
65
67
|
return method unless method.to_s.start_with? 'component_'
|
|
66
68
|
|
|
67
|
-
target.class.to_s.demodulize.underscore
|
|
69
|
+
"#{target.class.to_s.demodulize.underscore}_#{method.to_s.gsub(/^component_/, '')}"
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
def log_action(values)
|
|
71
73
|
values[:user] ||= values[:target].current_user if values[:target]
|
|
72
|
-
@mutex.synchronize { Ditty::AuditLog.create values }
|
|
74
|
+
@mutex.synchronize { ::Ditty::AuditLog.create values }
|
|
73
75
|
end
|
|
74
76
|
|
|
75
77
|
def user_traits(target)
|
|
@@ -84,4 +86,4 @@ module Ditty
|
|
|
84
86
|
end
|
|
85
87
|
end
|
|
86
88
|
|
|
87
|
-
Wisper.subscribe(Ditty::Listener.new) unless ENV['RACK_ENV'] == 'test'
|
|
89
|
+
Wisper.subscribe(::Ditty::Listener.new) unless ENV['RACK_ENV'] == 'test'
|
|
@@ -8,7 +8,7 @@ module Ditty
|
|
|
8
8
|
class AcceptExtension
|
|
9
9
|
attr_reader :env, :regex, :content_type
|
|
10
10
|
|
|
11
|
-
def initialize(app, regex =
|
|
11
|
+
def initialize(app, regex = %r{\A(.*)\.json(/?)\Z}, content_type = 'application/json')
|
|
12
12
|
# @mutex = Mutex.new
|
|
13
13
|
@app = app
|
|
14
14
|
@regex = regex
|
|
@@ -19,7 +19,7 @@ module Ditty
|
|
|
19
19
|
@env = env
|
|
20
20
|
|
|
21
21
|
request = Rack::Request.new(env)
|
|
22
|
-
if request.path
|
|
22
|
+
if request.path&.match?(regex)
|
|
23
23
|
request.path_info = request.path_info.gsub(regex, '\1\2')
|
|
24
24
|
env = request.env
|
|
25
25
|
env['ACCEPT'] = content_type
|
|
@@ -16,8 +16,8 @@ module Ditty
|
|
|
16
16
|
begin
|
|
17
17
|
@app.call env
|
|
18
18
|
rescue StandardError => e
|
|
19
|
-
::Ditty::Services::Logger.
|
|
20
|
-
::Ditty::Services::Logger.
|
|
19
|
+
::Ditty::Services::Logger.error "Ditty Catchall: #{e.class}"
|
|
20
|
+
::Ditty::Services::Logger.error e
|
|
21
21
|
[500, {}, ['Unknown Error']]
|
|
22
22
|
end
|
|
23
23
|
end
|
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
|
|
@@ -8,6 +9,14 @@ module Ditty
|
|
|
8
9
|
values
|
|
9
10
|
end
|
|
10
11
|
|
|
12
|
+
def display_id
|
|
13
|
+
self[:slug] || self[:guid] || self[:id]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def etag
|
|
17
|
+
Digest::SHA2.hexdigest values.to_json
|
|
18
|
+
end
|
|
19
|
+
|
|
11
20
|
alias for_csv for_json
|
|
12
21
|
end
|
|
13
22
|
end
|
|
@@ -37,6 +37,10 @@ module Ditty
|
|
|
37
37
|
}
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
def uid
|
|
41
|
+
user&.id
|
|
42
|
+
end
|
|
43
|
+
|
|
40
44
|
# Validation
|
|
41
45
|
def validate
|
|
42
46
|
super
|
|
@@ -55,7 +59,7 @@ module Ditty
|
|
|
55
59
|
# 1 Special Character
|
|
56
60
|
# 1 Number
|
|
57
61
|
# At least 8 characters
|
|
58
|
-
%r[\A(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#&$*)(}{%^=_+|\\:";'
|
|
62
|
+
%r[\A(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#&$*)(}{%^=_+|\\:";'<>,.\-/?\[\]])(?=.*[0-9]).{8,}\Z],
|
|
59
63
|
:password,
|
|
60
64
|
message: 'is not strong enough'
|
|
61
65
|
)
|
|
@@ -72,12 +76,12 @@ module Ditty
|
|
|
72
76
|
|
|
73
77
|
private
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
def encrypt_password
|
|
80
|
+
self.crypted_password = ::BCrypt::Password.create(password)
|
|
81
|
+
end
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
def password_required
|
|
84
|
+
crypted_password.blank? || !password.blank?
|
|
85
|
+
end
|
|
82
86
|
end
|
|
83
87
|
end
|