ditty 0.3.0 → 0.3.1
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/ditty.gemspec +1 -1
- data/lib/ditty/controllers/audit_logs.rb +15 -0
- data/lib/ditty/controllers/main.rb +4 -0
- data/lib/ditty/controllers/users.rb +16 -6
- data/lib/ditty/db.rb +13 -11
- data/lib/ditty/helpers/component.rb +26 -7
- data/lib/ditty/helpers/views.rb +1 -1
- data/lib/ditty/models/identity.rb +10 -1
- data/lib/ditty/policies/identity_policy.rb +1 -1
- data/lib/ditty/policies/user_policy.rb +0 -4
- data/lib/ditty/rake_tasks.rb +15 -7
- data/lib/ditty/version.rb +1 -1
- data/lib/ditty.rb +2 -1
- data/views/audit_logs/index.haml +2 -0
- data/views/identity/login.haml +4 -3
- data/views/identity/register.haml +2 -2
- data/views/partials/sidebar.haml +5 -4
- data/views/users/display.haml +2 -1
- data/views/users/profile.haml +9 -0
- data/views/users/user.haml +2 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c1aeccd30ff2045fdc743913e43590e7cc5ca03
|
4
|
+
data.tar.gz: 5c85c18dfd395210a4c64a11b9d801d8afaf2360
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9152764039916756b7c355de8466597f83f64921122e969f5dec13a5376c3310ab4d2c5e95576abf583bc86aa6a0ad0e1a60a7c3fdb0a8cde3b5946523d3fd22
|
7
|
+
data.tar.gz: c1df6170f906e47a460abb59a52ee4054ae5434daa926c6da8062cecda9e1554227efdfb936fd5204a848436cb08af55d1a7bcffa5b8f05870c8fba7fb57513d
|
data/ditty.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency 'timecop'
|
30
30
|
|
31
31
|
spec.add_dependency 'activesupport', '>= 3'
|
32
|
-
spec.add_dependency 'bcrypt', '~> 3.
|
32
|
+
spec.add_dependency 'bcrypt', '~> 3.1'
|
33
33
|
spec.add_dependency 'haml', '~> 5.0'
|
34
34
|
spec.add_dependency 'logger', '~> 1.0'
|
35
35
|
spec.add_dependency 'omniauth', '~> 1.0'
|
@@ -8,6 +8,21 @@ module Ditty
|
|
8
8
|
class AuditLogs < Ditty::Component
|
9
9
|
set model_class: AuditLog
|
10
10
|
|
11
|
+
FILTERS = [
|
12
|
+
{ name: :user, field: 'user.email' },
|
13
|
+
{ name: :action }
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
helpers do
|
17
|
+
def user_options
|
18
|
+
policy_scope(::Ditty::User).as_hash(:email, :email)
|
19
|
+
end
|
20
|
+
|
21
|
+
def action_options
|
22
|
+
policy_scope(::Ditty::AuditLog).as_hash(:action, :action)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
11
26
|
def find_template(views, name, engine, &block)
|
12
27
|
super(views, name, engine, &block) # Root
|
13
28
|
super(::Ditty::App.view_folder, name, engine, &block) # Ditty
|
@@ -45,12 +45,16 @@ module Ditty
|
|
45
45
|
|
46
46
|
# Register Page
|
47
47
|
get '/auth/identity/register' do
|
48
|
+
authorize ::Ditty::Identity, :register
|
49
|
+
|
48
50
|
identity = Identity.new
|
49
51
|
haml :'identity/register', locals: { title: 'Register', identity: identity }
|
50
52
|
end
|
51
53
|
|
52
54
|
# Register Action
|
53
55
|
post '/auth/identity/new' do
|
56
|
+
authorize ::Ditty::Identity, :register
|
57
|
+
|
54
58
|
identity = Identity.new(params['identity'])
|
55
59
|
if identity.valid? && identity.save
|
56
60
|
user = User.find_or_create(email: identity.username)
|
@@ -95,9 +95,12 @@ module Ditty
|
|
95
95
|
roles = values.delete('role_id')
|
96
96
|
entity.set values
|
97
97
|
if entity.valid? && entity.save
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
if roles
|
99
|
+
entity.remove_all_roles
|
100
|
+
roles.each { |role_id| entity.add_role(role_id) }
|
101
|
+
entity.check_roles
|
102
|
+
end
|
103
|
+
|
101
104
|
log_action("#{dehumanized}_update".to_sym) if settings.track_actions
|
102
105
|
respond_to do |format|
|
103
106
|
format.html do
|
@@ -112,7 +115,14 @@ module Ditty
|
|
112
115
|
end
|
113
116
|
end
|
114
117
|
else
|
115
|
-
|
118
|
+
respond_to do |format|
|
119
|
+
format.html do
|
120
|
+
haml :"#{view_location}/edit", locals: { entity: entity, title: heading(:edit) }
|
121
|
+
end
|
122
|
+
format.json do
|
123
|
+
400
|
124
|
+
end
|
125
|
+
end
|
116
126
|
end
|
117
127
|
end
|
118
128
|
|
@@ -140,8 +150,8 @@ module Ditty
|
|
140
150
|
if identity.valid? && identity.save
|
141
151
|
log_action("#{dehumanized}_update_password".to_sym) if settings.track_actions
|
142
152
|
flash[:success] = 'Password Updated'
|
143
|
-
redirect
|
144
|
-
elsif current_user.super_admin?
|
153
|
+
redirect back
|
154
|
+
elsif current_user.super_admin? && current_user.id != id
|
145
155
|
haml :"#{view_location}/display", locals: { entity: entity, identity: identity, title: heading }
|
146
156
|
else
|
147
157
|
haml :"#{view_location}/profile", locals: { entity: entity, identity: identity, title: heading }
|
data/lib/ditty/db.rb
CHANGED
@@ -3,16 +3,18 @@
|
|
3
3
|
require 'sequel'
|
4
4
|
require 'ditty/services/logger'
|
5
5
|
|
6
|
-
|
7
|
-
#
|
8
|
-
|
6
|
+
if ENV['DATABASE_URL']
|
7
|
+
# Delete DATABASE_URL from the environment, so it isn't accidently
|
8
|
+
# passed to subprocesses. DATABASE_URL may contain passwords.
|
9
|
+
DB = Sequel.connect(ENV['RACK_ENV'] == 'production' ? ENV.delete('DATABASE_URL') : ENV['DATABASE_URL'])
|
9
10
|
|
10
|
-
|
11
|
-
DB.
|
12
|
-
DB.
|
11
|
+
DB.sql_log_level = (ENV['SEQUEL_LOGGING_LEVEL'] || :debug).to_sym
|
12
|
+
DB.loggers << Ditty::Services::Logger.instance
|
13
|
+
DB.extension(:pagination)
|
13
14
|
|
14
|
-
Sequel::Model.plugin :validation_helpers
|
15
|
-
Sequel::Model.plugin :update_or_create
|
16
|
-
Sequel::Model.plugin :timestamps, update_on_create: true
|
17
|
-
|
18
|
-
|
15
|
+
Sequel::Model.plugin :validation_helpers
|
16
|
+
Sequel::Model.plugin :update_or_create
|
17
|
+
Sequel::Model.plugin :timestamps, update_on_create: true
|
18
|
+
else
|
19
|
+
Ditty::Services::Logger.instance.error 'No database connection set up'
|
20
|
+
end
|
@@ -49,23 +49,42 @@ module Ditty
|
|
49
49
|
|
50
50
|
def filtered(dataset)
|
51
51
|
filters.each do |filter|
|
52
|
-
next
|
52
|
+
next if [nil, ''].include? params[filter[:name].to_s]
|
53
53
|
filter[:field] ||= filter[:name]
|
54
|
+
filter[:modifier] ||= :to_s
|
54
55
|
dataset = apply_filter(dataset, filter)
|
55
56
|
end
|
56
57
|
dataset
|
57
58
|
end
|
58
59
|
|
59
60
|
def apply_filter(dataset, filter)
|
60
|
-
value = params[filter[:name].to_s]
|
61
|
-
return dataset
|
62
|
-
|
63
|
-
dataset.where(filter
|
61
|
+
value = params[filter[:name].to_s].send(filter[:modifier])
|
62
|
+
return dataset.where(filter[:field] => value) unless filter[:field].to_s.include? '.'
|
63
|
+
|
64
|
+
dataset.where(filter_field(filter) => filter_value(filter))
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_field(filter)
|
68
|
+
filter[:field].to_s.split('.').first.to_sym
|
69
|
+
end
|
70
|
+
|
71
|
+
def filter_value(filter)
|
72
|
+
field = filter[:field].to_s.split('.').last.to_sym
|
73
|
+
assoc = filter_association(filter)
|
74
|
+
value = params[filter[:name].to_s].send(filter[:modifier])
|
75
|
+
value = assoc.associated_dataset.first(field => value)
|
76
|
+
value.nil? ? assoc.associated_class.new : value
|
77
|
+
end
|
78
|
+
|
79
|
+
def filter_association(filter)
|
80
|
+
assoc = filter[:field].to_s.split('.').first.to_sym
|
81
|
+
assoc = settings.model_class.association_reflection(assoc)
|
82
|
+
raise "Unknown association #{assoc}" if assoc.nil?
|
83
|
+
assoc
|
64
84
|
end
|
65
85
|
|
66
86
|
def search(dataset)
|
67
|
-
return dataset if params['q']
|
68
|
-
return dataset if searchable_fields == []
|
87
|
+
return dataset if ['', nil].include?(params['q']) || searchable_fields == []
|
69
88
|
|
70
89
|
filters = searchable_fields.map { |f| Sequel.ilike(f.to_sym, "%#{params[:q]}%") }
|
71
90
|
dataset.where Sequel.|(*filters)
|
data/lib/ditty/helpers/views.rb
CHANGED
@@ -46,7 +46,16 @@ module Ditty
|
|
46
46
|
if password_required
|
47
47
|
validates_presence :password
|
48
48
|
validates_presence :password_confirmation
|
49
|
-
|
49
|
+
validates_format(
|
50
|
+
# 1 Uppercase
|
51
|
+
# 1 lowercase
|
52
|
+
# 1 Special Character
|
53
|
+
# 1 Number
|
54
|
+
# At least 8 characters
|
55
|
+
%r[\A(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#&$*)(}{%^=_+|\\:";'<>,.\-\/?\[\]])(?=.*[0-9]).{8,}\Z],
|
56
|
+
:password,
|
57
|
+
message: 'is not strong enough'
|
58
|
+
)
|
50
59
|
end
|
51
60
|
|
52
61
|
errors.add(:password_confirmation, 'must match password') if !password.blank? && password != password_confirmation
|
data/lib/ditty/rake_tasks.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'rake'
|
4
4
|
require 'rake/tasklib'
|
5
|
+
require 'ditty/db'
|
5
6
|
|
6
7
|
module Ditty
|
7
8
|
class Tasks < ::Rake::TaskLib
|
@@ -50,35 +51,42 @@ module Ditty
|
|
50
51
|
end
|
51
52
|
|
52
53
|
namespace :migrate do
|
54
|
+
require 'logger'
|
55
|
+
|
53
56
|
folder = 'migrations'
|
54
57
|
|
55
58
|
desc 'Check if the migration is current'
|
56
59
|
task :check do
|
57
|
-
|
60
|
+
::DB.loggers << Logger.new($stdout)
|
58
61
|
puts 'Running Ditty Migrations check'
|
59
62
|
::Sequel.extension :migration
|
60
|
-
|
63
|
+
begin
|
64
|
+
::Sequel::Migrator.check_current(::DB, folder)
|
65
|
+
puts 'Migrations up to date'
|
66
|
+
rescue Sequel::Migrator::Error => _e
|
67
|
+
puts 'Migrations NOT up to date'
|
68
|
+
end
|
61
69
|
end
|
62
70
|
|
63
71
|
desc 'Migrate Ditty database to latest version'
|
64
72
|
task :up do
|
65
|
-
|
73
|
+
::DB.loggers << Logger.new($stdout)
|
66
74
|
puts 'Running Ditty Migrations up'
|
67
75
|
::Sequel.extension :migration
|
68
76
|
::Sequel::Migrator.apply(::DB, folder)
|
69
77
|
end
|
70
78
|
|
71
|
-
desc '
|
79
|
+
desc 'Remove the whole Ditty database. You WILL lose data'
|
72
80
|
task :down do
|
73
|
-
|
81
|
+
::DB.loggers << Logger.new($stdout)
|
74
82
|
puts 'Running Ditty Migrations down'
|
75
83
|
::Sequel.extension :migration
|
76
84
|
::Sequel::Migrator.apply(::DB, folder, 0)
|
77
85
|
end
|
78
86
|
|
79
|
-
desc 'Reset the Ditty database'
|
87
|
+
desc 'Reset the Ditty database. You WILL lose data'
|
80
88
|
task :bounce do
|
81
|
-
|
89
|
+
::DB.loggers << Logger.new($stdout)
|
82
90
|
puts 'Running Ditty Migrations bounce'
|
83
91
|
::Sequel.extension :migration
|
84
92
|
::Sequel::Migrator.apply(::DB, folder, 0)
|
data/lib/ditty/version.rb
CHANGED
data/lib/ditty.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'ditty/version'
|
4
|
+
require 'ditty/services/logger'
|
4
5
|
|
5
6
|
module Ditty
|
6
7
|
class ComponentError < StandardError; end
|
@@ -57,7 +58,7 @@ module Ditty
|
|
57
58
|
#
|
58
59
|
# Ditty::Components.register_component(:component_name, ComponentModule)
|
59
60
|
def self.register_component(name, mod)
|
60
|
-
|
61
|
+
Ditty::Services::Logger.instance.info "Registering #{mod} as #{name}"
|
61
62
|
@components[name] = mod
|
62
63
|
end
|
63
64
|
|
data/views/audit_logs/index.haml
CHANGED
data/views/identity/login.haml
CHANGED
@@ -13,7 +13,8 @@
|
|
13
13
|
%label.control-label Password
|
14
14
|
%input.form-control.border-input{ name: 'password', type: 'password' }
|
15
15
|
%button.btn.btn-primary{ type: 'submit' } Log In
|
16
|
-
.
|
17
|
-
|
18
|
-
|
16
|
+
- if policy(::Ditty::Identity).register?
|
17
|
+
.pull-right
|
18
|
+
No account yet?
|
19
|
+
%a.btn.btn-default{ href: "#{settings.map_path}/auth/identity/register" } Register
|
19
20
|
.col-sm-3
|
@@ -3,10 +3,10 @@
|
|
3
3
|
.col-md-8
|
4
4
|
.panel.panel-default
|
5
5
|
.panel-heading
|
6
|
-
%h4
|
6
|
+
%h4 Register
|
7
7
|
.panel-body
|
8
8
|
%form.form-horizontal{ method: 'post', action: "#{settings.map_path}/auth/identity/new" }
|
9
|
-
= form_control(:username, identity, label: '
|
9
|
+
= form_control(:username, identity, label: 'Username', placeholder: 'Your username')
|
10
10
|
= form_control(:password, identity, label: 'Password', type: :password)
|
11
11
|
= form_control(:password_confirmation, identity, label: 'Confirm Password', type: :password)
|
12
12
|
|
data/views/partials/sidebar.haml
CHANGED
@@ -30,7 +30,8 @@
|
|
30
30
|
%a{ href: "#{settings.map_path}/auth/identity" }
|
31
31
|
%i.fa.fa-user.fa-fw
|
32
32
|
Log In
|
33
|
-
|
34
|
-
%
|
35
|
-
%
|
36
|
-
|
33
|
+
- if policy(::Ditty::Identity).register?
|
34
|
+
%li
|
35
|
+
%a{ href: "#{settings.map_path}/auth/identity/register" }
|
36
|
+
%i.fa.fa-pencil-square-o.fa-fw
|
37
|
+
Register
|
data/views/users/display.haml
CHANGED
@@ -23,7 +23,8 @@
|
|
23
23
|
|
24
24
|
.row
|
25
25
|
.col-md-6
|
26
|
-
|
26
|
+
- if policy(entity).update?
|
27
|
+
%a.btn.btn-default{ href: "#{base_path}/#{entity.id}/edit" } Edit
|
27
28
|
.col-md-6.text-right
|
28
29
|
- if policy(entity).delete?
|
29
30
|
%form{ method: 'post', action: "#{base_path}/#{entity.id}" }
|
data/views/users/profile.haml
CHANGED
@@ -20,6 +20,15 @@
|
|
20
20
|
%p.description
|
21
21
|
%label Signed up:
|
22
22
|
= entity.created_at.strftime('%Y-%m-%d %H:%M:%S')
|
23
|
+
.row
|
24
|
+
.col-md-6
|
25
|
+
- if policy(entity).update?
|
26
|
+
%a.btn.btn-default{ href: "#{base_path}/#{entity.id}/edit" } Edit
|
27
|
+
.col-md-6.text-right
|
28
|
+
- if policy(entity).delete?
|
29
|
+
%form{ method: 'post', action: "#{base_path}/#{entity.id}" }
|
30
|
+
%input{ name: '_method', value: 'DELETE', type: 'hidden' }
|
31
|
+
%button.btn.btn-warning{ type: 'submit' } Delete
|
23
32
|
.col-md-2
|
24
33
|
|
25
34
|
.row
|
data/views/users/user.haml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
1
|
= form_control(:name, user)
|
2
2
|
= form_control(:surname, user)
|
3
|
-
|
3
|
+
- if policy(user).permitted_attributes.include? :role_id
|
4
|
+
= form_control(:role_id, user, type: 'select', options: Ditty::Role.as_hash(:id, :name), name: 'user[role_id][]', field: :roles, multiple: true)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ditty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jurgens du Toit
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '3.
|
131
|
+
version: '3.1'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '3.
|
138
|
+
version: '3.1'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: haml
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|