ditty 0.2.0

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.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.pryrc +6 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +15 -0
  6. data/.travis.yml +15 -0
  7. data/Gemfile.ci +19 -0
  8. data/License.txt +7 -0
  9. data/Rakefile +10 -0
  10. data/Readme.md +67 -0
  11. data/config.ru +33 -0
  12. data/ditty.gemspec +46 -0
  13. data/lib/ditty/components/app.rb +78 -0
  14. data/lib/ditty/controllers/application.rb +79 -0
  15. data/lib/ditty/controllers/audit_logs.rb +44 -0
  16. data/lib/ditty/controllers/component.rb +161 -0
  17. data/lib/ditty/controllers/main.rb +86 -0
  18. data/lib/ditty/controllers/roles.rb +16 -0
  19. data/lib/ditty/controllers/users.rb +183 -0
  20. data/lib/ditty/db.rb +12 -0
  21. data/lib/ditty/helpers/authentication.rb +58 -0
  22. data/lib/ditty/helpers/component.rb +63 -0
  23. data/lib/ditty/helpers/pundit.rb +34 -0
  24. data/lib/ditty/helpers/views.rb +50 -0
  25. data/lib/ditty/helpers/wisper.rb +14 -0
  26. data/lib/ditty/listener.rb +23 -0
  27. data/lib/ditty/models/audit_log.rb +14 -0
  28. data/lib/ditty/models/base.rb +7 -0
  29. data/lib/ditty/models/identity.rb +70 -0
  30. data/lib/ditty/models/role.rb +16 -0
  31. data/lib/ditty/models/user.rb +63 -0
  32. data/lib/ditty/policies/application_policy.rb +21 -0
  33. data/lib/ditty/policies/audit_log_policy.rb +41 -0
  34. data/lib/ditty/policies/identity_policy.rb +25 -0
  35. data/lib/ditty/policies/role_policy.rb +41 -0
  36. data/lib/ditty/policies/user_policy.rb +47 -0
  37. data/lib/ditty/rake_tasks.rb +85 -0
  38. data/lib/ditty/seed.rb +1 -0
  39. data/lib/ditty/services/logger.rb +48 -0
  40. data/lib/ditty/version.rb +5 -0
  41. data/lib/ditty.rb +142 -0
  42. data/migrate/20170207_base_tables.rb +40 -0
  43. data/migrate/20170208_audit_log.rb +12 -0
  44. data/migrate/20170416_audit_log_details.rb +9 -0
  45. data/public/browserconfig.xml +9 -0
  46. data/public/images/apple-icon.png +0 -0
  47. data/public/images/favicon-16x16.png +0 -0
  48. data/public/images/favicon-32x32.png +0 -0
  49. data/public/images/launcher-icon-1x.png +0 -0
  50. data/public/images/launcher-icon-2x.png +0 -0
  51. data/public/images/launcher-icon-4x.png +0 -0
  52. data/public/images/mstile-150x150.png +0 -0
  53. data/public/images/safari-pinned-tab.svg +43 -0
  54. data/public/manifest.json +25 -0
  55. data/views/404.haml +7 -0
  56. data/views/audit_logs/index.haml +30 -0
  57. data/views/error.haml +4 -0
  58. data/views/identity/login.haml +19 -0
  59. data/views/identity/register.haml +14 -0
  60. data/views/index.haml +1 -0
  61. data/views/layout.haml +55 -0
  62. data/views/partials/delete_form.haml +4 -0
  63. data/views/partials/footer.haml +5 -0
  64. data/views/partials/form_control.haml +20 -0
  65. data/views/partials/navbar.haml +24 -0
  66. data/views/partials/notifications.haml +24 -0
  67. data/views/partials/pager.haml +14 -0
  68. data/views/partials/sidebar.haml +35 -0
  69. data/views/roles/display.haml +18 -0
  70. data/views/roles/edit.haml +11 -0
  71. data/views/roles/form.haml +1 -0
  72. data/views/roles/index.haml +22 -0
  73. data/views/roles/new.haml +10 -0
  74. data/views/users/display.haml +50 -0
  75. data/views/users/edit.haml +11 -0
  76. data/views/users/identity.haml +3 -0
  77. data/views/users/index.haml +23 -0
  78. data/views/users/new.haml +11 -0
  79. data/views/users/profile.haml +39 -0
  80. data/views/users/user.haml +3 -0
  81. metadata +431 -0
data/views/404.haml ADDED
@@ -0,0 +1,7 @@
1
+ %h2 Whoops!
2
+
3
+ %p.lead
4
+ We could not find the page you were looking for...
5
+
6
+ .text-center
7
+ %iframe{ width: 560, height: 315, src: 'https://www.youtube.com/embed/e3-5YC_oHjE', frameborder: 0, allowfullscreen: true }
@@ -0,0 +1,30 @@
1
+ .row
2
+ .col-md-12
3
+ .panel.panel-default
4
+ %table.table.table-striped
5
+ %thead
6
+ %tr
7
+ %th User email
8
+ %th Action
9
+ %th Details
10
+ %th Created at
11
+ %tbody
12
+ - if list.count > 0
13
+ - list.all.each do |entity|
14
+ %tr
15
+ %td
16
+ -if entity.user
17
+ %a{ href: "/users/#{entity.user.id}" }= entity.user.email
18
+ -else
19
+ None
20
+ %td
21
+ = entity.action
22
+ %td
23
+ = entity.details
24
+ %td
25
+ = entity.created_at.strftime('%Y-%m-%d %H:%M:%S')
26
+ - else
27
+ %tr
28
+ %td.text-center{ colspan: 4 } No records
29
+
30
+ =pagination(list, base_path)
data/views/error.haml ADDED
@@ -0,0 +1,4 @@
1
+ %h2 Whoops!
2
+
3
+ %p.lead
4
+ = error.class
@@ -0,0 +1,19 @@
1
+ .row
2
+ .col-sm-3
3
+ .col-sm-6
4
+ .panel.panel-default
5
+ .panel-heading
6
+ %h4 Login
7
+ .panel-body
8
+ %form{ method: 'post', action: "#{settings.map_path}/auth/identity/callback" }
9
+ .form-group
10
+ %label.control-label Username
11
+ %input.form-control.border-input{ name: 'username' }
12
+ .form-group
13
+ %label.control-label Password
14
+ %input.form-control.border-input{ name: 'password', type: 'password' }
15
+ %button.btn.btn-primary{ type: 'submit' } Log In
16
+ .pull-right
17
+ No account yet?
18
+ %a.btn.btn-default{ href: "#{settings.map_path}/auth/identity/register" } Register
19
+ .col-sm-3
@@ -0,0 +1,14 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-heading
6
+ %h4 Ditty Registration
7
+ .panel-body
8
+ %form.form-horizontal{ method: 'post', action: "#{settings.map_path}/auth/identity/new" }
9
+ = form_control(:username, identity, label: 'Email', placeholder: 'Your email address')
10
+ = form_control(:password, identity, label: 'Password', type: :password)
11
+ = form_control(:password_confirmation, identity, label: 'Confirm Password', type: :password)
12
+
13
+ %button.btn.btn-primary{ type: 'submit' } Register
14
+ .col-md-2
data/views/index.haml ADDED
@@ -0,0 +1 @@
1
+ %h2 Hello! Ready to get this Ditty started?
data/views/layout.haml ADDED
@@ -0,0 +1,55 @@
1
+ !!! 5
2
+ %html{ lang: 'en' }
3
+ %head
4
+ %meta{ charset: 'utf-8' }
5
+ %meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
6
+ %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
7
+ %meta{ name: 'theme-color', content: '#ffffff' }
8
+ %link{ rel: 'manifest', href: '/manifest.json' }
9
+ %link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/images/favicon-32x32.png' }
10
+ %link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '/images/favicon-16x16.png' }
11
+ %link{ rel: 'apple-touch-icon', sizes: '76x76', href: '/images/apple-icon.png' }
12
+ %link{ rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#5bbad5' }
13
+
14
+ %title
15
+ Ditty
16
+ - if defined? title
17
+ = "- #{title}"
18
+
19
+ %meta{ name: 'description', content: '' }
20
+ %meta{ name: 'author', content: '' }
21
+
22
+ / Le styles
23
+ %link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', media: 'screen' }
24
+ %link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/css/sb-admin-2.min.css', media: 'screen' }
25
+ %link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/metisMenu/2.5.2/metisMenu.min.css', media: 'screen' }
26
+ %link{ rel: 'stylesheet', href: 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css', media: 'screen' }
27
+ /[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
28
+ /[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
29
+
30
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js' }
31
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/js/sb-admin-2.min.js' }
32
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/metisMenu/2.5.2/metisMenu.min.js' }
33
+ %body
34
+ #wrapper
35
+ = haml :'partials/navbar', locals: { title: (defined?(title) ? title : 'Ditty') }
36
+ #page-wrapper
37
+ .row
38
+ .col-md-12
39
+ -if defined? title
40
+ %h1.page-header= title
41
+ = haml :'partials/notifications'
42
+
43
+ = yield
44
+ = haml :'partials/footer'
45
+
46
+
47
+ / Placed at the end of the document so the pages load faster
48
+ %script{ type: 'text/javascript', src: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js' }
49
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.min.js' }
50
+ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.bundle.min.js' }
51
+ :javascript
52
+ $(function() {
53
+ $('.sidebar-nav').metisMenu();
54
+ });
55
+
@@ -0,0 +1,4 @@
1
+ <form method="post" action="<%= base_path %>/<%= entity.id %>">
2
+ <input type="hidden" name="_method" value="DELETE">
3
+ <button type="submit" class="btn btn-danger"><%= delete_label %></button>
4
+ </form>
@@ -0,0 +1,5 @@
1
+ %footer.footer.text-muted.text-center
2
+ %hr
3
+ .copyright
4
+ :plain
5
+ &copy; <script>document.write(new Date().getFullYear())</script>, Automation Exchange
@@ -0,0 +1,20 @@
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(', ')
@@ -0,0 +1,24 @@
1
+ .navbar.navbar-default.navbar-static-top{ role: 'navigation', style: 'margin-bottom: 0' }
2
+ .navbar-header
3
+ %button.navbar-toggle.collapsed{ 'type' => 'button', 'data-toggle' => 'collapse', 'data-target' => '.navbar-collapse' }
4
+ %span.sr-only Toggle navigation
5
+ %span.icon-bar
6
+ %span.icon-bar
7
+ %span.icon-bar
8
+ %span.navbar-brand
9
+ Ditty
10
+
11
+ -if authenticated?
12
+ %form.nav.navbar-top-links.navbar-form.navbar-right{ action: "#{settings.map_path}/auth/identity", method: 'post' }
13
+ %a.btn.btn-default{ href: "#{settings.map_path}/users/profile" } My Account
14
+ %input{ name: '_method', value: 'DELETE', type: 'hidden' }
15
+ %button.btn.btn-default{ type: 'submit' }
16
+ / %i.ti-panel
17
+ Logout
18
+ - else
19
+ %ul.nav.navbar-top-links.navbar-right
20
+ %li
21
+ %a.btn.btn-link{ href: "#{settings.map_path}/auth/identity" }
22
+ Log In
23
+ .navbar-default.sidebar{ role: 'navigation' }
24
+ = haml :'partials/sidebar'
@@ -0,0 +1,24 @@
1
+ - if flash[:danger]
2
+ .alert.alert-danger.alert-dismissible{ role: "alert" }
3
+ %button.close{ 'type' => 'button', 'aria-hidden' => 'true', 'area-label' => 'true', 'data-dismiss' => 'alert' } &times;
4
+ - (flash[:danger].is_a?(Array) ? flash[:danger] : [flash[:danger]]).each do |msg|
5
+ %span= msg
6
+
7
+ - if flash[:warning]
8
+ .alert.alert-warning.alert-dismissible{ role: "alert" }
9
+ %button.close{ 'type' => 'button', 'aria-hidden' => 'true', 'area-label' => 'true', 'data-dismiss' => 'alert' } &times;
10
+ - (flash[:warning].is_a?(Array) ? flash[:warning] : [flash[:warning]]).each do |msg|
11
+ %span= msg
12
+
13
+ - if flash[:success]
14
+ .alert.alert-success.alert-dismissible{ role: "alert" }
15
+ %button.close{ 'type' => 'button', 'aria-hidden' => 'true', 'area-label' => 'true', 'data-dismiss' => 'alert' } &times;
16
+ - (flash[:success].is_a?(Array) ? flash[:success] : [flash[:success]]).each do |msg|
17
+ %span= msg
18
+
19
+
20
+ - if flash[:info]
21
+ .alert.alert-info.alert-dismissible{ role: "alert" }
22
+ %button.close{ 'type' => 'button', 'aria-hidden' => 'true', 'area-label' => 'true', 'data-dismiss' => 'alert' } &times;
23
+ - (flash[:info].is_a?(Array) ? flash[:info] : [flash[:info]]).each do |msg|
24
+ %span= msg
@@ -0,0 +1,14 @@
1
+ %nav{"aria-label" => "Page navigation"}
2
+ - if list.pagination_record_count > 0
3
+ %p.text-center Showing #{list.current_page_record_range} of #{list.pagination_record_count} records
4
+ %ul.pager
5
+ %li
6
+ %a{href: "#{base_path}?page=1&count=#{list.page_size}"} First
7
+ %li{class: ("disabled" if list.first_page?)}
8
+ %a{href: prev_link} Previous
9
+ %li{class: ("disabled" if list.last_page?)}
10
+ %a{href: next_link} Next
11
+ %li
12
+ %a{href: "#{base_path}?page=#{list.page_count}&count=#{list.page_size}"} Last
13
+ - else
14
+ %p.text-center No records to show
@@ -0,0 +1,35 @@
1
+ .sidebar-nav.navbar-collapse
2
+ %ul.nav.nav-pills.nav-stacked
3
+ - if authenticated?
4
+ %li
5
+ %a{ href: "#{settings.map_path}/" }
6
+ %i.fa.fa-home.fa-fw
7
+ Home
8
+ - Ditty::Components.navigation.each do |item|
9
+ - if item[:target].nil? || policy(item[:target]).list?
10
+ - if item[:group]
11
+ %li
12
+ %a{ href: '#' }
13
+ %i.fa.fa-fw{ class: "fa-#{item[:icon]}" }
14
+ =item[:group]
15
+ %span.fa.arrow
16
+ %ul.nav.nav-second-level
17
+ - item[:items].each do |sub_item|
18
+ %li
19
+ %a{ href: "#{settings.map_path}#{sub_item[:link]}" }
20
+ %i.fa.fa-fw{ class: "fa-#{sub_item[:icon]}" }
21
+ = sub_item[:text]
22
+ - else
23
+ %li
24
+ %a{ href: "#{settings.map_path}#{item[:link]}" }
25
+ %i.fa.fa-fw{ class: "fa-#{item[:icon]}" }
26
+ = item[:text]
27
+ - else
28
+ %li.active
29
+ %a{ href: "#{settings.map_path}/auth/identity" }
30
+ %i.fa.fa-user.fa-fw
31
+ Log In
32
+ %li
33
+ %a{ href: "#{settings.map_path}/auth/identity/register" }
34
+ %i.fa.fa-pencil-square-o.fa-fw
35
+ Register
@@ -0,0 +1,18 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ %p.description
7
+ %label Name:
8
+ = entity.name
9
+
10
+ .row
11
+ .col-md-6
12
+ %a.btn.btn-default{ href: "#{base_path}/#{entity.id}/edit" } Edit
13
+ .col-md-6.text-right
14
+ - if policy(entity).delete?
15
+ %form{ method: 'post', action: "#{base_path}/#{entity.id}" }
16
+ %input{ name: '_method', value: 'DELETE', type: 'hidden' }
17
+ %button.btn.btn-warning{ type: 'submit' } Delete
18
+ .col-md-2
@@ -0,0 +1,11 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}" }
7
+ %input{ name: '_method', value: 'PUT', type: 'hidden' }
8
+ = haml :'roles/form', locals: { entity: entity }
9
+ %button.btn.btn-primary{ type: 'submit' }
10
+ Update Role
11
+ .col-md-2
@@ -0,0 +1 @@
1
+ = form_control(:name, entity)
@@ -0,0 +1,22 @@
1
+ .row
2
+ .col-md-12
3
+ .panel.panel-default
4
+ %table.table.table-striped
5
+ %thead
6
+ %tr
7
+ %th Name
8
+ %tbody
9
+ - if list.count > 0
10
+ - list.all.each do |entity|
11
+ %tr
12
+ %td
13
+ %a{ href: "#{base_path}/#{entity.id}" }= entity.name
14
+ - else
15
+ %tr
16
+ %td.text-center{ colspan: 1 } No records
17
+
18
+ - if policy(::Ditty::Role).create?
19
+ .panel-body.text-right
20
+ %a.btn.btn-primary{ href: "#{base_path}/new" } New Role
21
+
22
+ =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
+ %form.form-horizontal{ method: 'post', action: base_path }
7
+ = haml :'roles/form', locals: { entity: entity }
8
+ %button.btn.btn-primary{ type: 'submit' }
9
+ Create Role
10
+ .col-md-2
@@ -0,0 +1,50 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ .author
7
+ %img.pull-right.thumbnail{ src: entity.gravatar }
8
+ %h4= entity.email
9
+
10
+ %hr
11
+ %p.description
12
+ %label Name:
13
+ = entity.name
14
+ %p.description
15
+ %label Surname:
16
+ = entity.surname
17
+ %p.description
18
+ %label Roles:
19
+ = entity.roles_dataset.map(:name).map(&:titlecase).join(', ')
20
+ %p.description
21
+ %label Signed up:
22
+ = entity.created_at.strftime('%Y-%m-%d %H:%M:%S')
23
+
24
+ .row
25
+ .col-md-6
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
32
+ .col-md-2
33
+
34
+ - if entity.identity.first
35
+ .row
36
+ .col-md-2
37
+ .col-md-8
38
+ .panel.panel-default
39
+ .panel-heading
40
+ %h4 Change Password
41
+ .panel-body
42
+ %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}/identity" }
43
+ %input{ name: '_method', value: 'PUT', type: 'hidden' }
44
+ = form_control(:password, entity.identity.first, type: 'password', placeholder: 'Your password', group: 'identity')
45
+ = form_control(:password_confirmation, entity.identity.first, type: 'password', label: 'Confirm Password', placeholder: 'Confirm your password', group: 'identity')
46
+ %button.btn.btn-primary{ type: 'submit' }
47
+ Change Password
48
+ .col-md-2
49
+
50
+
@@ -0,0 +1,11 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}" }
7
+ %input{ name: '_method', value: 'PUT', type: 'hidden' }
8
+ = haml :'users/user', locals: { user: entity }
9
+ %button.btn.btn-primary{ type: 'submit' }
10
+ Update User
11
+ .col-md-2
@@ -0,0 +1,3 @@
1
+ = form_control(:username, identity, label: 'Email', placeholder: 'Your email address')
2
+ = form_control(:password, identity, type: 'password', placeholder: 'Your password')
3
+ = form_control(:password_confirmation, identity, type: 'password', label: 'Confirm Password', placeholder: 'Confirm your password')
@@ -0,0 +1,23 @@
1
+ .row
2
+ .col-md-12
3
+ .panel.panel-default
4
+ %table.table.table-striped
5
+ %thead
6
+ %tr
7
+ %th Email
8
+ %th Name
9
+ %th Surname
10
+ %th Roles
11
+ %tbody
12
+ - list.all.each do |entity|
13
+ %tr
14
+ %td
15
+ %a{ href: "#{base_path}/#{entity.id}" }= entity.email
16
+ %td= entity.name
17
+ %td= entity.surname
18
+ %td= entity.roles_dataset.map(:name).map(&:titlecase).join(', ')
19
+ - if policy(::Ditty::User).create?
20
+ .panel-body.text-right
21
+ %a.btn.btn-primary{ href: "#{base_path}/new" } New User
22
+
23
+ =pagination(list, base_path)
@@ -0,0 +1,11 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ %form.form-horizontal{ method: 'post', action: base_path }
7
+ = haml :'users/identity', locals: { identity: identity }
8
+ = haml :'users/user', locals: { user: entity }
9
+ %button.btn.btn-primary{ type: 'submit' }
10
+ Create User
11
+ .col-md-2
@@ -0,0 +1,39 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .panel.panel-default
5
+ .panel-body
6
+ .author
7
+ %img.pull-right.thumbnail{ src: entity.gravatar }
8
+ %h4= entity.email
9
+
10
+ %hr
11
+ %p.description
12
+ %label Name:
13
+ = entity.name
14
+ %p.description
15
+ %label Surname:
16
+ = entity.surname
17
+ %p.description
18
+ %label Roles:
19
+ = entity.roles_dataset.map(:name).map(&:titlecase).join(', ')
20
+ %p.description
21
+ %label Signed up:
22
+ = entity.created_at.strftime('%Y-%m-%d %H:%M:%S')
23
+ .col-md-2
24
+
25
+ .row
26
+ .col-md-2
27
+ .col-md-8
28
+ .panel.panel-default
29
+ .panel-heading
30
+ %h4 Change Password
31
+ .panel-body
32
+ %form.form-horizontal{ method: 'post', action: "#{base_path}/#{entity.id}/identity" }
33
+ %input{ name: '_method', value: 'PUT', type: 'hidden' }
34
+ = form_control(:old_password, identity, type: 'password', placeholder: 'Your current password')
35
+ = form_control(:password, identity, type: 'password', placeholder: 'Your new password')
36
+ = form_control(:password_confirmation, identity, type: 'password', label: 'Confirm Password', placeholder: 'Confirm your password')
37
+ %button.btn.btn-primary{ type: 'submit' }
38
+ Change Password
39
+ .col-md-2
@@ -0,0 +1,3 @@
1
+ = form_control(:name, user)
2
+ = form_control(:surname, user)
3
+ = form_control(:role_id, user, type: 'select', options: Ditty::Role.as_hash(:id, :name), name: 'user[role_id][]', field: :roles, multiple: true)