ditty 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -7
  3. data/.travis.yml +5 -5
  4. data/Gemfile.ci +2 -0
  5. data/Rakefile +4 -3
  6. data/Readme.md +24 -2
  7. data/ditty.gemspec +4 -3
  8. data/lib/ditty.rb +24 -0
  9. data/lib/ditty/cli.rb +6 -2
  10. data/lib/ditty/components/app.rb +10 -1
  11. data/lib/ditty/controllers/application.rb +72 -10
  12. data/lib/ditty/controllers/audit_logs.rb +1 -5
  13. data/lib/ditty/controllers/auth.rb +37 -17
  14. data/lib/ditty/controllers/component.rb +15 -5
  15. data/lib/ditty/controllers/main.rb +1 -5
  16. data/lib/ditty/controllers/roles.rb +2 -5
  17. data/lib/ditty/controllers/user_login_traits.rb +18 -0
  18. data/lib/ditty/controllers/users.rb +4 -9
  19. data/lib/ditty/db.rb +3 -1
  20. data/lib/ditty/emails/base.rb +13 -4
  21. data/lib/ditty/helpers/authentication.rb +6 -5
  22. data/lib/ditty/helpers/component.rb +9 -1
  23. data/lib/ditty/helpers/response.rb +24 -3
  24. data/lib/ditty/helpers/views.rb +20 -0
  25. data/lib/ditty/listener.rb +38 -10
  26. data/lib/ditty/middleware/accept_extension.rb +2 -0
  27. data/lib/ditty/middleware/error_catchall.rb +2 -0
  28. data/lib/ditty/models/audit_log.rb +1 -0
  29. data/lib/ditty/models/base.rb +4 -0
  30. data/lib/ditty/models/identity.rb +3 -0
  31. data/lib/ditty/models/role.rb +1 -0
  32. data/lib/ditty/models/user.rb +9 -1
  33. data/lib/ditty/models/user_login_trait.rb +17 -0
  34. data/lib/ditty/policies/audit_log_policy.rb +6 -6
  35. data/lib/ditty/policies/role_policy.rb +2 -2
  36. data/lib/ditty/policies/user_login_trait_policy.rb +45 -0
  37. data/lib/ditty/policies/user_policy.rb +2 -2
  38. data/lib/ditty/rubocop.rb +3 -0
  39. data/lib/ditty/seed.rb +2 -0
  40. data/lib/ditty/services/authentication.rb +7 -2
  41. data/lib/ditty/services/email.rb +8 -2
  42. data/lib/ditty/services/logger.rb +11 -0
  43. data/lib/ditty/services/pagination_wrapper.rb +2 -0
  44. data/lib/ditty/services/settings.rb +14 -3
  45. data/lib/ditty/tasks/ditty.rake +109 -0
  46. data/lib/ditty/tasks/omniauth-ldap.rake +43 -0
  47. data/lib/ditty/version.rb +1 -1
  48. data/lib/rubocop/cop/ditty/call_services_directly.rb +42 -0
  49. data/migrate/20181209_add_user_login_traits.rb +16 -0
  50. data/migrate/20181209_extend_audit_log.rb +12 -0
  51. data/views/403.haml +2 -0
  52. data/views/audit_logs/index.haml +11 -6
  53. data/views/auth/ldap.haml +17 -0
  54. data/views/emails/forgot_password.haml +1 -1
  55. data/views/emails/layouts/action.haml +10 -6
  56. data/views/emails/layouts/alert.haml +2 -1
  57. data/views/emails/layouts/billing.haml +2 -1
  58. data/views/error.haml +8 -3
  59. data/views/partials/form_control.haml +24 -20
  60. data/views/partials/navbar.haml +11 -12
  61. data/views/partials/sidebar.haml +1 -1
  62. data/views/roles/index.haml +2 -0
  63. data/views/user_login_traits/display.haml +32 -0
  64. data/views/user_login_traits/edit.haml +10 -0
  65. data/views/user_login_traits/form.haml +5 -0
  66. data/views/user_login_traits/index.haml +30 -0
  67. data/views/user_login_traits/new.haml +10 -0
  68. data/views/users/display.haml +1 -1
  69. data/views/users/login_traits.haml +27 -0
  70. data/views/users/profile.haml +2 -0
  71. metadata +50 -21
  72. data/lib/ditty/rake_tasks.rb +0 -102
@@ -3,7 +3,8 @@
3
3
  %head
4
4
  %meta{:content => "width=device-width", :name => "viewport"}/
5
5
  %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
6
- %title Alerts e.g. approaching your limit
6
+ %title
7
+ = subject
7
8
  :css
8
9
  img {
9
10
  max-width: 100%;
@@ -3,7 +3,8 @@
3
3
  %head
4
4
  %meta{:content => "width=device-width", :name => "viewport"}/
5
5
  %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
6
- %title Billing e.g. invoices and receipts
6
+ %title
7
+ = subject
7
8
  :css
8
9
  img {
9
10
  max-width: 100%;
@@ -1,4 +1,9 @@
1
- %h2 Whoops!
1
+ - if ENV['APP_ENV'] != 'production'
2
+ %p.lead
3
+ = error.class
4
+ %br
5
+ %small
6
+ = error.message
2
7
 
3
- %p.lead
4
- = error.class
8
+ %pre
9
+ = error.backtrace.join("\n")
@@ -1,20 +1,24 @@
1
- %div{ class: "form-group#{model.errors[field] ? ' has-error' : ''}" }
2
- %label.col-sm-3.control-label{ for: attributes[:id] }= label
3
- .col-sm-9
4
- - type = attributes.delete(:type)
5
- - if type == 'select'
6
- - options = attributes.delete(:options)
7
- %select{attributes}
8
- - if attributes[:multiple]
9
- - options.each do |k,v| k ||= v; v ||= k;
10
- %option{ value: k, selected: (model.send(field).map(&:id).include? k)}= v
11
- - else
12
- %option{ value: ""} -- Select One --
13
- - options.each do |k,v| k ||= v; v ||= k;
14
- %option{ value: k, selected: [model[field].to_s, default].include?(k.to_s)}= v
15
- - elsif type == 'textarea'
16
- %textarea{attributes}= preserve(model[field])
17
- - else
18
- %input{attributes, type: type, value: model[field] || default}
19
- - if model.errors[field]
20
- %p.help-block.text-danger= model.errors[field].join(', ')
1
+ - type = attributes.delete(:type)
2
+ - if type == 'hidden'
3
+ %input{attributes, type: type, value: model[field] || default}
4
+ - else
5
+ %div{ class: "form-group#{model.errors[field] ? ' has-error' : ''}" }
6
+ - if type != 'file'
7
+ %label.col-sm-3.control-label{ for: attributes[:id] }= label
8
+ .col-sm-9
9
+ - if type == 'select'
10
+ - options = attributes.delete(:options)
11
+ %select{attributes}
12
+ - if attributes[:multiple]
13
+ - options.each do |k,v| k ||= v; v ||= k;
14
+ %option{ value: k, selected: (model.send(field).map(&:id).include? k)}= v
15
+ - else
16
+ %option{ value: ""} -- Select One --
17
+ - options.each do |k,v| k ||= v; v ||= k;
18
+ %option{ value: k, selected: [model[field].to_s, default].include?(k.to_s)}= v
19
+ - elsif type == 'textarea'
20
+ %textarea{attributes}= preserve(model[field] || default)
21
+ - else
22
+ %input{attributes, type: type, value: model[field] || default}
23
+ - if model.errors[field]
24
+ %p.help-block.text-danger= model.errors[field].join(', ')
@@ -6,18 +6,17 @@
6
6
  %span.icon-bar
7
7
  %span.icon-bar
8
8
  %span.navbar-brand
9
- Ditty
9
+ = config('ditty.title', 'Ditty')
10
+
11
+ %nav.nav.navbar-top-links.navbar-right.navbar-form{ style: 'border: 0;' }
12
+ - if authenticated?
13
+ = delete_form_tag("#{settings.map_path}/auth") do
14
+ %a.btn.btn-default{ href: "#{settings.map_path}/users/profile" } My Account
15
+ %button.btn.btn-default{ type: 'submit' }
16
+ Logout
17
+ - else
18
+ %a.btn.btn-default{ href: "#{settings.map_path}/auth/login" }
19
+ Log In
10
20
 
11
- -if authenticated?
12
- = delete_form_tag("#{settings.map_path}/auth", attributes: { class: 'nav navbar-top-links navbar-form navbar-right' }) do
13
- %a.btn.btn-default{ href: "#{settings.map_path}/users/profile" } My Account
14
- %button.btn.btn-default{ type: 'submit' }
15
- / %i.ti-panel
16
- Logout
17
- - else
18
- %ul.nav.navbar-top-links.navbar-right
19
- %li
20
- %a.btn.btn-link{ href: "#{settings.map_path}/auth/login" }
21
- Log In
22
21
  .navbar-default.sidebar{ role: 'navigation' }
23
22
  = haml :'partials/sidebar'
@@ -26,7 +26,7 @@
26
26
  %i.fa.fa-fw{ class: "fa-#{item[:icon]}" }
27
27
  = item[:text]
28
28
  - else
29
- %li.active
29
+ %li
30
30
  %a{ href: "#{settings.map_path}/auth/login" }
31
31
  %i.fa.fa-user.fa-fw
32
32
  Log In
@@ -1,6 +1,8 @@
1
1
  .row
2
2
  .col-md-12
3
3
  .panel.panel-default
4
+ .panel-body
5
+ = haml :'partials/search'
4
6
  %table.table.table-striped
5
7
  %thead
6
8
  %tr
@@ -0,0 +1,32 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ %p.description
7
+ %label User:
8
+ = entity.user&.email || 'Unknown'
9
+ %p.description
10
+ %label IP Address:
11
+ = entity.ip_address || 'Unknown'
12
+ %p.description
13
+ %label Device:
14
+ = entity.device || 'Unknown'
15
+ %p.description
16
+ %label Platform:
17
+ = entity.platform || 'Unknown'
18
+ %p.description
19
+ %label Browser:
20
+ = entity.browser || 'Unknown'
21
+ %p.description
22
+ %label Last Seen:
23
+ = entity.updated_at.strftime('%F %T')
24
+
25
+ .row
26
+ .col-md-6
27
+ %a.btn.btn-default{ href: "#{base_path}/#{entity.id}/edit" } Edit
28
+ .col-md-6.text-right
29
+ - if policy(entity).delete?
30
+ = delete_form_tag("#{base_path}/#{entity.id}") do
31
+ %button.btn.btn-warning{ type: 'submit' } Delete
32
+ .col-md-2
@@ -0,0 +1,10 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ = edit_form_tag "#{base_path}/#{entity.id}" do
7
+ = haml :'user_login_traits/form', locals: { entity: entity }
8
+ %button.btn.btn-primary{ type: 'submit' }
9
+ Update Login Trait
10
+ .col-md-2
@@ -0,0 +1,5 @@
1
+ = form_control(:ip_address, entity)
2
+ = form_control(:device, entity)
3
+ = form_control(:platform, entity)
4
+ = form_control(:browser, entity)
5
+ = form_control(:updated_at, entity)
@@ -0,0 +1,30 @@
1
+ .row
2
+ .col-md-12
3
+ .panel.panel-default
4
+ .panel-body
5
+ = haml :'partials/search'
6
+ %table.table.table-striped
7
+ %thead
8
+ %tr
9
+ %th User
10
+ %th IP Address
11
+ %th Device
12
+ %th Platform
13
+ %th Browser
14
+ %th Last Seen
15
+ %tbody
16
+ - if list.count.positive?
17
+ - list.all.each do |entity|
18
+ %tr
19
+ %td= entity.user&.email || 'Unknown'
20
+ %td
21
+ %a{ href: "#{base_path}/#{entity.id}" }= entity.ip_address || 'Unknown'
22
+ %td= entity.device || 'Unknown'
23
+ %td= entity.platform || 'Unknown'
24
+ %td= entity.browser || 'Unknown'
25
+ %td= entity.updated_at
26
+ - else
27
+ %tr
28
+ %td.text-center{ colspan: 6 } No records
29
+
30
+ =pagination(list, base_path)
@@ -0,0 +1,10 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ = new_form_tag base_path do
7
+ = haml :'user_login_traits/form', locals: { entity: entity }
8
+ %button.btn.btn-primary{ type: 'submit' }
9
+ Create Login Trait
10
+ .col-md-2
@@ -46,4 +46,4 @@
46
46
  Change Password
47
47
  .col-md-2
48
48
 
49
-
49
+ = haml :'users/login_traits', locals: { user_login_traits: entity.user_login_traits }
@@ -0,0 +1,27 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-heading
6
+ %h4 Logins
7
+ %table.table
8
+ %thead
9
+ %tr
10
+ %th IP Address
11
+ %th Device
12
+ %th Platform
13
+ %th Browser
14
+ %th Last Seen
15
+ %tbody
16
+ - if user_login_traits.count.positive?
17
+ - user_login_traits.each do |trait|
18
+ %tr
19
+ %td= trait.ip_address
20
+ %td= trait.device
21
+ %td= trait.platform
22
+ %td= trait.browser
23
+ %td= trait.updated_at.strftime('%F %T')
24
+ - else
25
+ %tr
26
+ %td.text-center{ colspan: 5 } No Records
27
+ .col-md-2
@@ -44,3 +44,5 @@
44
44
  %button.btn.btn-primary{ type: 'submit' }
45
45
  Change Password
46
46
  .col-md-2
47
+
48
+ = haml :'users/login_traits', locals: { user_login_traits: entity.user_login_traits }
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ditty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
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: 2018-09-03 00:00:00.000000000 Z
11
+ date: 2019-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.12'
19
+ version: '1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.12'
26
+ version: '1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: database_cleaner
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '3.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: browser
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.5'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.5'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: haml
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -165,33 +179,33 @@ dependencies:
165
179
  - !ruby/object:Gem::Version
166
180
  version: '1.0'
167
181
  - !ruby/object:Gem::Dependency
168
- name: oga
182
+ name: mail
169
183
  requirement: !ruby/object:Gem::Requirement
170
184
  requirements:
171
185
  - - ">="
172
186
  - !ruby/object:Gem::Version
173
- version: '2.14'
187
+ version: '1.7'
174
188
  type: :runtime
175
189
  prerelease: false
176
190
  version_requirements: !ruby/object:Gem::Requirement
177
191
  requirements:
178
192
  - - ">="
179
193
  - !ruby/object:Gem::Version
180
- version: '2.14'
194
+ version: '1.7'
181
195
  - !ruby/object:Gem::Dependency
182
- name: mail
196
+ name: oga
183
197
  requirement: !ruby/object:Gem::Requirement
184
198
  requirements:
185
199
  - - ">="
186
200
  - !ruby/object:Gem::Version
187
- version: '1.7'
201
+ version: '2.14'
188
202
  type: :runtime
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
206
  - - ">="
193
207
  - !ruby/object:Gem::Version
194
- version: '1.7'
208
+ version: '2.14'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: omniauth
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -347,33 +361,33 @@ dependencies:
347
361
  - !ruby/object:Gem::Version
348
362
  version: '1.5'
349
363
  - !ruby/object:Gem::Dependency
350
- name: tilt
364
+ name: thor
351
365
  requirement: !ruby/object:Gem::Requirement
352
366
  requirements:
353
367
  - - ">="
354
368
  - !ruby/object:Gem::Version
355
- version: '2'
369
+ version: '0.20'
356
370
  type: :runtime
357
371
  prerelease: false
358
372
  version_requirements: !ruby/object:Gem::Requirement
359
373
  requirements:
360
374
  - - ">="
361
375
  - !ruby/object:Gem::Version
362
- version: '2'
376
+ version: '0.20'
363
377
  - !ruby/object:Gem::Dependency
364
- name: thor
378
+ name: tilt
365
379
  requirement: !ruby/object:Gem::Requirement
366
380
  requirements:
367
381
  - - ">="
368
382
  - !ruby/object:Gem::Version
369
- version: '0.20'
383
+ version: '2'
370
384
  type: :runtime
371
385
  prerelease: false
372
386
  version_requirements: !ruby/object:Gem::Requirement
373
387
  requirements:
374
388
  - - ">="
375
389
  - !ruby/object:Gem::Version
376
- version: '0.20'
390
+ version: '2'
377
391
  - !ruby/object:Gem::Dependency
378
392
  name: will_paginate
379
393
  requirement: !ruby/object:Gem::Requirement
@@ -432,6 +446,7 @@ files:
432
446
  - lib/ditty/controllers/component.rb
433
447
  - lib/ditty/controllers/main.rb
434
448
  - lib/ditty/controllers/roles.rb
449
+ - lib/ditty/controllers/user_login_traits.rb
435
450
  - lib/ditty/controllers/users.rb
436
451
  - lib/ditty/db.rb
437
452
  - lib/ditty/emails/base.rb
@@ -449,23 +464,30 @@ files:
449
464
  - lib/ditty/models/identity.rb
450
465
  - lib/ditty/models/role.rb
451
466
  - lib/ditty/models/user.rb
467
+ - lib/ditty/models/user_login_trait.rb
452
468
  - lib/ditty/policies/application_policy.rb
453
469
  - lib/ditty/policies/audit_log_policy.rb
454
470
  - lib/ditty/policies/identity_policy.rb
455
471
  - lib/ditty/policies/role_policy.rb
472
+ - lib/ditty/policies/user_login_trait_policy.rb
456
473
  - lib/ditty/policies/user_policy.rb
457
- - lib/ditty/rake_tasks.rb
474
+ - lib/ditty/rubocop.rb
458
475
  - lib/ditty/seed.rb
459
476
  - lib/ditty/services/authentication.rb
460
477
  - lib/ditty/services/email.rb
461
478
  - lib/ditty/services/logger.rb
462
479
  - lib/ditty/services/pagination_wrapper.rb
463
480
  - lib/ditty/services/settings.rb
481
+ - lib/ditty/tasks/ditty.rake
482
+ - lib/ditty/tasks/omniauth-ldap.rake
464
483
  - lib/ditty/version.rb
484
+ - lib/rubocop/cop/ditty/call_services_directly.rb
465
485
  - migrate/20170207_base_tables.rb
466
486
  - migrate/20170208_audit_log.rb
467
487
  - migrate/20170416_audit_log_details.rb
468
488
  - migrate/20180307_password_reset.rb
489
+ - migrate/20181209_add_user_login_traits.rb
490
+ - migrate/20181209_extend_audit_log.rb
469
491
  - public/browserconfig.xml
470
492
  - public/images/apple-icon.png
471
493
  - public/images/favicon-16x16.png
@@ -477,10 +499,12 @@ files:
477
499
  - public/images/safari-pinned-tab.svg
478
500
  - public/manifest.json
479
501
  - views/400.haml
502
+ - views/403.haml
480
503
  - views/404.haml
481
504
  - views/audit_logs/index.haml
482
505
  - views/auth/forgot_password.haml
483
506
  - views/auth/identity.haml
507
+ - views/auth/ldap.haml
484
508
  - views/auth/login.haml
485
509
  - views/auth/register.haml
486
510
  - views/auth/register_identity.haml
@@ -510,10 +534,16 @@ files:
510
534
  - views/roles/form.haml
511
535
  - views/roles/index.haml
512
536
  - views/roles/new.haml
537
+ - views/user_login_traits/display.haml
538
+ - views/user_login_traits/edit.haml
539
+ - views/user_login_traits/form.haml
540
+ - views/user_login_traits/index.haml
541
+ - views/user_login_traits/new.haml
513
542
  - views/users/display.haml
514
543
  - views/users/edit.haml
515
544
  - views/users/identity.haml
516
545
  - views/users/index.haml
546
+ - views/users/login_traits.haml
517
547
  - views/users/new.haml
518
548
  - views/users/profile.haml
519
549
  - views/users/user.haml
@@ -536,8 +566,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
536
566
  - !ruby/object:Gem::Version
537
567
  version: '0'
538
568
  requirements: []
539
- rubyforge_project:
540
- rubygems_version: 2.7.7
569
+ rubygems_version: 3.0.2
541
570
  signing_key:
542
571
  specification_version: 4
543
572
  summary: Sinatra Based Application Framework