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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.env.test +2 -0
  3. data/.gitignore +3 -0
  4. data/.pryrc +2 -0
  5. data/.rubocop.yml +23 -4
  6. data/.travis.yml +4 -8
  7. data/CNAME +1 -0
  8. data/Dockerfile +18 -0
  9. data/Gemfile.ci +0 -17
  10. data/Rakefile +2 -2
  11. data/_config.yml +1 -0
  12. data/config.ru +4 -4
  13. data/ditty.gemspec +28 -18
  14. data/docs/CNAME +1 -0
  15. data/docs/_config.yml +1 -0
  16. data/docs/index.md +34 -0
  17. data/exe/ditty +2 -0
  18. data/lib/ditty/cli.rb +41 -5
  19. data/lib/ditty/components/{app.rb → ditty.rb} +18 -16
  20. data/lib/ditty/controllers/{application.rb → application_controller.rb} +63 -34
  21. data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +4 -2
  22. data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +22 -18
  23. data/lib/ditty/controllers/{component.rb → component_controller.rb} +23 -20
  24. data/lib/ditty/controllers/{main.rb → main_controller.rb} +6 -2
  25. data/lib/ditty/controllers/roles_controller.rb +23 -0
  26. data/lib/ditty/controllers/user_login_traits_controller.rb +46 -0
  27. data/lib/ditty/controllers/{users.rb → users_controller.rb} +13 -11
  28. data/lib/ditty/db.rb +7 -5
  29. data/lib/ditty/emails/base.rb +37 -32
  30. data/lib/ditty/generators/crud_generator.rb +114 -0
  31. data/lib/ditty/generators/migration_generator.rb +26 -0
  32. data/lib/ditty/generators/project_generator.rb +52 -0
  33. data/lib/ditty/helpers/component.rb +2 -1
  34. data/lib/ditty/helpers/pundit.rb +24 -8
  35. data/lib/ditty/helpers/response.rb +15 -13
  36. data/lib/ditty/helpers/views.rb +28 -6
  37. data/lib/ditty/listener.rb +6 -4
  38. data/lib/ditty/memcached.rb +8 -0
  39. data/lib/ditty/middleware/accept_extension.rb +2 -2
  40. data/lib/ditty/middleware/error_catchall.rb +2 -2
  41. data/lib/ditty/models/base.rb +9 -0
  42. data/lib/ditty/models/identity.rb +11 -7
  43. data/lib/ditty/models/role.rb +1 -0
  44. data/lib/ditty/models/user.rb +23 -2
  45. data/lib/ditty/policies/role_policy.rb +1 -1
  46. data/lib/ditty/policies/user_login_trait_policy.rb +1 -1
  47. data/lib/ditty/policies/user_policy.rb +1 -1
  48. data/lib/ditty/services/authentication.rb +27 -16
  49. data/lib/ditty/services/email.rb +19 -15
  50. data/lib/ditty/services/logger.rb +26 -20
  51. data/lib/ditty/services/pagination_wrapper.rb +7 -5
  52. data/lib/ditty/services/settings.rb +7 -6
  53. data/lib/ditty/tasks/ditty.rake +19 -1
  54. data/lib/ditty/tasks/omniauth-ldap.rake +2 -2
  55. data/lib/ditty/templates/.gitignore +5 -0
  56. data/lib/ditty/templates/.rspec +2 -0
  57. data/lib/ditty/templates/.rubocop.yml +7 -0
  58. data/lib/ditty/templates/Rakefile +12 -0
  59. data/lib/ditty/templates/application.rb +12 -0
  60. data/lib/ditty/templates/config.ru +37 -0
  61. data/lib/ditty/templates/controller.rb.erb +64 -0
  62. data/lib/ditty/templates/env.example +4 -0
  63. data/lib/ditty/templates/lib/project.rb.erb +5 -0
  64. data/lib/ditty/templates/logs/.empty_directory +0 -0
  65. data/lib/ditty/templates/migration.rb.erb +7 -0
  66. data/lib/ditty/templates/model.rb.erb +26 -0
  67. data/lib/ditty/templates/pids/.empty_directory +0 -0
  68. data/lib/ditty/templates/policy.rb.erb +48 -0
  69. data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
  70. data/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
  71. data/lib/ditty/templates/public/css/styles.css +13 -0
  72. data/lib/ditty/templates/public/favicon.ico +0 -0
  73. data/{public → lib/ditty/templates/public}/images/apple-icon.png +0 -0
  74. data/{public → lib/ditty/templates/public}/images/favicon-16x16.png +0 -0
  75. data/{public → lib/ditty/templates/public}/images/favicon-32x32.png +0 -0
  76. data/{public → lib/ditty/templates/public}/images/launcher-icon-1x.png +0 -0
  77. data/{public → lib/ditty/templates/public}/images/launcher-icon-2x.png +0 -0
  78. data/{public → lib/ditty/templates/public}/images/launcher-icon-4x.png +0 -0
  79. data/{public → lib/ditty/templates/public}/images/mstile-150x150.png +0 -0
  80. data/{public → lib/ditty/templates/public}/images/safari-pinned-tab.svg +0 -0
  81. data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
  82. data/lib/ditty/templates/public/js/scripts.js +1 -0
  83. data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
  84. data/lib/ditty/templates/settings.yml.erb +29 -0
  85. data/lib/ditty/templates/sidekiq.rb +18 -0
  86. data/lib/ditty/templates/sidekiq.yml +9 -0
  87. data/lib/ditty/templates/spec_helper.rb +43 -0
  88. data/lib/ditty/templates/type.rb.erb +21 -0
  89. data/lib/ditty/templates/views/display.haml.tt +20 -0
  90. data/lib/ditty/templates/views/edit.haml.tt +10 -0
  91. data/lib/ditty/templates/views/form.haml.tt +11 -0
  92. data/lib/ditty/templates/views/index.haml.tt +29 -0
  93. data/lib/ditty/templates/views/new.haml.tt +10 -0
  94. data/lib/ditty/version.rb +1 -1
  95. data/lib/ditty.rb +6 -4
  96. data/lib/rubocop/cop/ditty/call_services_directly.rb +2 -2
  97. data/migrate/20181209_add_user_login_traits.rb +4 -4
  98. data/migrate/20190220_add_parent_id_to_roles.rb +9 -0
  99. data/spec/ditty/api_spec.rb +51 -0
  100. data/spec/ditty/controllers/roles_spec.rb +67 -0
  101. data/spec/ditty/controllers/user_login_traits_spec.rb +72 -0
  102. data/spec/ditty/controllers/users_spec.rb +72 -0
  103. data/spec/ditty/emails/base_spec.rb +76 -0
  104. data/spec/ditty/emails/forgot_password_spec.rb +20 -0
  105. data/spec/ditty/helpers/component_spec.rb +85 -0
  106. data/spec/ditty/models/user_spec.rb +36 -0
  107. data/spec/ditty/services/email_spec.rb +36 -0
  108. data/spec/ditty/services/logger_spec.rb +68 -0
  109. data/spec/ditty/services/settings_spec.rb +63 -0
  110. data/spec/ditty_spec.rb +9 -0
  111. data/spec/factories.rb +46 -0
  112. data/spec/fixtures/logger.yml +17 -0
  113. data/spec/fixtures/section.yml +3 -0
  114. data/spec/fixtures/settings.yml +8 -0
  115. data/spec/spec_helper.rb +51 -0
  116. data/spec/support/api_shared_examples.rb +250 -0
  117. data/spec/support/crud_shared_examples.rb +145 -0
  118. data/views/403.haml +1 -1
  119. data/views/404.haml +2 -4
  120. data/views/500.haml +11 -0
  121. data/views/audit_logs/index.haml +32 -33
  122. data/views/auth/forgot_password.haml +32 -16
  123. data/views/auth/identity.haml +14 -13
  124. data/views/auth/ldap.haml +2 -2
  125. data/views/auth/login.haml +23 -17
  126. data/views/auth/register.haml +20 -18
  127. data/views/auth/register_identity.haml +27 -12
  128. data/views/auth/reset_password.haml +36 -19
  129. data/views/blank.haml +43 -0
  130. data/views/embedded.haml +17 -11
  131. data/views/index.haml +1 -1
  132. data/views/layout.haml +45 -30
  133. data/views/partials/actions.haml +15 -14
  134. data/views/partials/content_tag.haml +0 -0
  135. data/views/partials/delete_form.haml +1 -1
  136. data/views/partials/filter_control.haml +2 -2
  137. data/views/partials/footer.haml +6 -5
  138. data/views/partials/form_control.haml +19 -12
  139. data/views/partials/form_tag.haml +1 -1
  140. data/views/partials/navitems.haml +42 -0
  141. data/views/partials/notifications.haml +12 -8
  142. data/views/partials/pager.haml +44 -25
  143. data/views/partials/search.haml +15 -11
  144. data/views/partials/sidebar.haml +15 -37
  145. data/views/partials/sort_ui.haml +2 -0
  146. data/views/partials/topbar.haml +53 -0
  147. data/views/partials/user_associations.haml +32 -0
  148. data/views/quick_start.haml +23 -0
  149. data/views/roles/display.haml +27 -6
  150. data/views/roles/edit.haml +3 -3
  151. data/views/roles/form.haml +1 -0
  152. data/views/roles/index.haml +23 -16
  153. data/views/roles/new.haml +2 -2
  154. data/views/user_login_traits/display.haml +4 -4
  155. data/views/user_login_traits/edit.haml +3 -3
  156. data/views/user_login_traits/index.haml +23 -25
  157. data/views/user_login_traits/new.haml +2 -2
  158. data/views/users/display.haml +14 -15
  159. data/views/users/edit.haml +3 -3
  160. data/views/users/form.haml +0 -0
  161. data/views/users/index.haml +31 -24
  162. data/views/users/login_traits.haml +6 -8
  163. data/views/users/new.haml +2 -2
  164. data/views/users/profile.haml +15 -15
  165. data/views/users/user.haml +1 -1
  166. metadata +271 -63
  167. data/lib/ditty/controllers/roles.rb +0 -13
  168. data/lib/ditty/controllers/user_login_traits.rb +0 -18
  169. data/views/partials/navbar.haml +0 -22
@@ -0,0 +1,10 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .card.card-default.shadow
5
+ .card-body
6
+ = edit_form_tag "#{base_path}/#{entity.display_id}" do
7
+ = haml :'<%= model_name.pluralize.underscore %>/form', locals: { entity: entity }
8
+ %button.btn.btn-primary{ type: 'submit' }
9
+ Update <%= model_name %>
10
+ .col-md-2
@@ -0,0 +1,11 @@
1
+ <%- if columns.include? :user_id -%>
2
+ = form_control(:user_id, entity, type: 'select', options: policy_scope(Ditty::User).order(:email).as_hash(:id, :email))
3
+ <%- end -%>
4
+ <%- many_to_ones.each do |rel| -%>
5
+ <%- next if %i[users].include?(rel[:tablename]) -%>
6
+ = form_control(:<%= rel[:columns].first %>, entity, type: 'select', options: policy_scope(<%= namespace %>::<%= rel[:table].to_s.classify %>).order(:<%= name_column(rel[:table]) %>).as_hash(:id, :<%= name_column(rel[:table]) %>))
7
+ <%- end -%>
8
+ <%- (columns - meta_columns).each do |col| -%>
9
+ <%- next if %i[id guid].include?(name) || (name.to_s =~ /_id/ && info[:type] == :integer) -%>
10
+ = form_control(:<%= col %>, entity, type: '<%= input_types[schema[col][:type]] %>')
11
+ <%- end -%>
@@ -0,0 +1,29 @@
1
+ .row
2
+ .col-md-12
3
+ = haml :'partials/search'
4
+ %table.table.table-striped.table-bordered.table-hover
5
+ %thead.thead-dark
6
+ %tr
7
+ <%- columns.each do |col| -%>
8
+ %th <%= col.to_s.titleize %>
9
+ <%- end %>
10
+ %th
11
+ %tbody
12
+ - if list.count > 0
13
+ - list.all.each do |entity|
14
+ %tr
15
+ <%- columns.each do |col| -%>
16
+ %td= entity.<%= col %>
17
+ <%- end %>
18
+ %td
19
+ %a{ href: "#{base_path}/#{entity.display_id}", title: 'Show' }
20
+ %i.fa.fa-search
21
+ - if policy(entity).update?
22
+ %a{ href: "#{base_path}/#{entity.display_id}/edit", title: 'Edit' }
23
+ %i.fa.fa-edit
24
+ - else
25
+ %tr
26
+ %td.text-center{ colspan: <%= columns.count + 1 %> } No <%= model_name.pluralize %>
27
+
28
+ - if list.count > 0
29
+ = pagination(list, base_path)
@@ -0,0 +1,10 @@
1
+ .row
2
+ .col-md-2
3
+ .col-md-8
4
+ .card.card-default.shadow
5
+ .card-body
6
+ = new_form_tag base_path do
7
+ = haml :'<%= model_name.pluralize.underscore %>/form', locals: { entity: entity }
8
+ %button.btn.btn-primary{ type: 'submit' }
9
+ Create <%= model_name %>
10
+ .col-md-2
data/lib/ditty/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ditty
4
- VERSION = '0.8.0'
4
+ VERSION = '0.10.2'
5
5
  end
data/lib/ditty.rb CHANGED
@@ -62,7 +62,9 @@ module Ditty
62
62
  h = @components
63
63
  unless (component = h[name])
64
64
  require "ditty/components/#{name}"
65
- raise ComponentError, "Component #{name} did not register itself correctly in Ditty::Components" unless (component = h[name])
65
+ unless (component = h[name])
66
+ raise ComponentError, "Component #{name} did not register itself correctly in Ditty::Components"
67
+ end
66
68
  end
67
69
  component
68
70
  end
@@ -76,7 +78,7 @@ module Ditty
76
78
  #
77
79
  # Ditty::Components.register_component(:component_name, ComponentModule)
78
80
  def self.register_component(name, mod)
79
- Ditty::Services::Logger.instance.info "Registering #{mod} as #{name}"
81
+ ::Ditty::Services::Logger.info "Registering #{mod} as #{name}"
80
82
  @components[name] = mod
81
83
  end
82
84
 
@@ -94,9 +96,9 @@ module Ditty
94
96
 
95
97
  # Return an ordered list of navigation items:
96
98
  # `[{order:0, link:'/users/', text:'Users'}, {order:1, link:'/roles/', text:'Roles'}]
97
- def self.navigation
99
+ def self.navigation(request)
98
100
  nav = components.each_with_object([]) do |comp, memo|
99
- memo.concat comp[1].navigation if comp[1].respond_to?(:navigation)
101
+ memo.concat comp[1].navigation(request) if comp[1].respond_to?(:navigation)
100
102
  end
101
103
  nav.sort_by { |v| v[:order] }
102
104
  end
@@ -13,10 +13,10 @@ module RuboCop
13
13
  #
14
14
  # @example
15
15
  # # bad
16
- # Ditty::Services::Logger.instance.info 'This is a log message'
16
+ # ::Ditty::Services::Logger.instance.info 'This is a log message'
17
17
  #
18
18
  # # good
19
- # Ditty::Services::Logger.info 'This is a log message'
19
+ # ::Ditty::Services::Logger.info 'This is a log message'
20
20
  class CallServicesDirectly < RuboCop::Cop::Cop
21
21
  MSG = 'Do not use `.instance` on services. Call the method directly instead'
22
22
 
@@ -5,10 +5,10 @@ Sequel.migration do
5
5
  create_table :user_login_traits do
6
6
  primary_key :id
7
7
  foreign_key :user_id, :users
8
- String :ip_address, nullable: true
9
- String :platform, nullable: true
10
- String :device, nullable: true
11
- String :browser, nullable: true
8
+ String :ip_address, null: true
9
+ String :platform, null: true
10
+ String :device, null: true
11
+ String :browser, null: true
12
12
  DateTime :created_at
13
13
  DateTime :updated_at
14
14
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ alter_table :roles do
6
+ add_column :parent_id, Integer
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ Dir.glob('./lib/ditty/controllers/*.rb').sort.each { |f| require f }
5
+ require 'support/api_shared_examples'
6
+
7
+ describe ::Ditty::RolesController, type: :controller do
8
+ def app
9
+ described_class
10
+ end
11
+
12
+ let(:user) { create(:super_admin_user) }
13
+
14
+ before do
15
+ env 'rack.session', 'user_id' => user.id
16
+ end
17
+
18
+ it_behaves_like 'an API interface', :role, {}
19
+ end
20
+
21
+ describe ::Ditty::UsersController, type: :controller do
22
+ def app
23
+ described_class
24
+ end
25
+
26
+ let(:user) { create(:super_admin_user) }
27
+
28
+ before { env 'rack.session', 'user_id' => user.id }
29
+
30
+ params = {
31
+ identity: {
32
+ username: 'test-user@abc.abc',
33
+ password: 'som3Password!',
34
+ password_confirmation: 'som3Password!'
35
+ }
36
+ }
37
+
38
+ it_behaves_like 'an API interface', :user, params
39
+ end
40
+
41
+ describe ::Ditty::UserLoginTraitsController, type: :controller do
42
+ def app
43
+ described_class
44
+ end
45
+
46
+ let(:user) { create(:super_admin_user) }
47
+
48
+ before { env 'rack.session', 'user_id' => user.id }
49
+
50
+ it_behaves_like 'an API interface', :user_login_trait, {}
51
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/controllers/roles_controller'
5
+ require 'support/crud_shared_examples'
6
+
7
+ describe ::Ditty::RolesController do
8
+ def app
9
+ described_class
10
+ end
11
+
12
+ context 'as super_admin_user' do
13
+ let(:user) { create(:super_admin_user) }
14
+ let(:model) { create(app.model_class.name.to_sym) }
15
+ let(:create_data) do
16
+ group = described_class.model_class.to_s.demodulize.underscore
17
+ { group => build(described_class.model_class.name.to_sym).to_hash }
18
+ end
19
+ let(:update_data) do
20
+ group = described_class.model_class.to_s.demodulize.underscore
21
+ { group => build(described_class.model_class.name.to_sym).to_hash }
22
+ end
23
+ let(:invalid_create_data) do
24
+ group = described_class.model_class.to_s.demodulize.underscore
25
+ { group => { name: '' } }
26
+ end
27
+ let(:invalid_update_data) do
28
+ group = described_class.model_class.to_s.demodulize.underscore
29
+ { group => { name: '' } }
30
+ end
31
+
32
+ before do
33
+ # Log in
34
+ env 'rack.session', 'user_id' => user.id
35
+ end
36
+
37
+ it_behaves_like 'a CRUD Controller', '/roles'
38
+ end
39
+
40
+ context 'as user' do
41
+ let(:user) { create(:user) }
42
+ let(:model) { create(app.model_class.name.to_sym) }
43
+ let(:create_data) do
44
+ group = described_class.model_class.to_s.demodulize.underscore
45
+ { group => build(described_class.model_class.name.to_sym).to_hash }
46
+ end
47
+ let(:update_data) do
48
+ group = described_class.model_class.to_s.demodulize.underscore
49
+ { group => build(described_class.model_class.name.to_sym).to_hash }
50
+ end
51
+ let(:invalid_create_data) do
52
+ group = described_class.model_class.to_s.demodulize.underscore
53
+ { group => { name: '' } }
54
+ end
55
+ let(:invalid_update_data) do
56
+ group = described_class.model_class.to_s.demodulize.underscore
57
+ { group => { name: '' } }
58
+ end
59
+
60
+ before do
61
+ # Log in
62
+ env 'rack.session', 'user_id' => user.id
63
+ end
64
+
65
+ it_behaves_like 'a CRUD Controller', '/roles'
66
+ end
67
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/controllers/user_login_traits_controller'
5
+ require 'support/crud_shared_examples'
6
+
7
+ describe ::Ditty::UserLoginTraitsController do
8
+ def app
9
+ described_class
10
+ end
11
+
12
+ context 'as super_admin_user' do
13
+ let(:user) { create(:super_admin_user) }
14
+ let(:model) { create(app.model_class.name.to_sym) }
15
+ let(:create_data) do
16
+ group = described_class.model_class.to_s.demodulize.underscore
17
+ identity = build(:identity).to_hash
18
+ identity['password_confirmation'] = identity['password'] = 'som3Password!'
19
+ {
20
+ group => build(described_class.model_class.name.to_sym).to_hash,
21
+ 'identity' => identity
22
+ }
23
+ end
24
+ let(:update_data) do
25
+ group = described_class.model_class.to_s.demodulize.underscore
26
+ { group => build(described_class.model_class.name.to_sym).to_hash }
27
+ end
28
+ let(:invalid_create_data) do
29
+ group = described_class.model_class.to_s.demodulize.underscore
30
+ { group => { user_id: nil } }
31
+ end
32
+ let(:invalid_update_data) do
33
+ group = described_class.model_class.to_s.demodulize.underscore
34
+ { group => { user_id: nil } }
35
+ end
36
+
37
+ before do
38
+ # Log in
39
+ env 'rack.session', 'user_id' => user.id
40
+ end
41
+
42
+ it_behaves_like 'a CRUD Controller', '/user-login-traits'
43
+ end
44
+
45
+ context 'as user' do
46
+ let(:user) { create(:user) }
47
+ let(:model) { create(app.model_class.name.to_sym, user: user) }
48
+ let(:create_data) do
49
+ group = described_class.model_class.to_s.demodulize.underscore
50
+ { group => build(described_class.model_class.name.to_sym).to_hash }
51
+ end
52
+ let(:update_data) do
53
+ group = described_class.model_class.to_s.demodulize.underscore
54
+ { group => build(described_class.model_class.name.to_sym).to_hash }
55
+ end
56
+ let(:invalid_create_data) do
57
+ group = described_class.model_class.to_s.demodulize.underscore
58
+ { group => { user_id: nil } }
59
+ end
60
+ let(:invalid_update_data) do
61
+ group = described_class.model_class.to_s.demodulize.underscore
62
+ { group => { user_id: nil } }
63
+ end
64
+
65
+ before do
66
+ # Log in
67
+ env 'rack.session', 'user_id' => user.id
68
+ end
69
+
70
+ it_behaves_like 'a CRUD Controller', '/user-login-traits'
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/controllers/users_controller'
5
+ require 'support/crud_shared_examples'
6
+
7
+ describe ::Ditty::UsersController do
8
+ def app
9
+ described_class
10
+ end
11
+
12
+ context 'as super_admin_user' do
13
+ let(:user) { create(:super_admin_user) }
14
+ let(:model) { create(app.model_class.name.to_sym) }
15
+ let(:create_data) do
16
+ group = described_class.model_class.to_s.demodulize.underscore
17
+ identity = build(:identity).to_hash
18
+ identity['password_confirmation'] = identity['password'] = 'som3Password!'
19
+ {
20
+ group => build(described_class.model_class.name.to_sym).to_hash,
21
+ 'identity' => identity
22
+ }
23
+ end
24
+ let(:update_data) do
25
+ group = described_class.model_class.to_s.demodulize.underscore
26
+ { group => build(described_class.model_class.name.to_sym).to_hash }
27
+ end
28
+ let(:invalid_create_data) do
29
+ group = described_class.model_class.to_s.demodulize.underscore
30
+ { group => { email: 'invalidemail' } }
31
+ end
32
+ let(:invalid_update_data) do
33
+ group = described_class.model_class.to_s.demodulize.underscore
34
+ { group => { email: 'invalidemail' } }
35
+ end
36
+
37
+ before do
38
+ # Log in
39
+ env 'rack.session', 'user_id' => user.id
40
+ end
41
+
42
+ it_behaves_like 'a CRUD Controller', '/users'
43
+ end
44
+
45
+ context 'as user' do
46
+ let(:user) { create(:user) }
47
+ let(:model) { create(app.model_class.name.to_sym) }
48
+ let(:create_data) do
49
+ group = described_class.model_class.to_s.demodulize.underscore
50
+ { group => build(described_class.model_class.name.to_sym).to_hash }
51
+ end
52
+ let(:update_data) do
53
+ group = described_class.model_class.to_s.demodulize.underscore
54
+ { group => build(described_class.model_class.name.to_sym).to_hash }
55
+ end
56
+ let(:invalid_create_data) do
57
+ group = described_class.model_class.to_s.demodulize.underscore
58
+ { group => { email: 'invalidemail' } }
59
+ end
60
+ let(:invalid_update_data) do
61
+ group = described_class.model_class.to_s.demodulize.underscore
62
+ { group => { email: 'invalidemail' } }
63
+ end
64
+
65
+ before do
66
+ # Log in
67
+ env 'rack.session', 'user_id' => user.id
68
+ end
69
+
70
+ it_behaves_like 'a CRUD Controller', '/users'
71
+ end
72
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/emails/base'
5
+ require 'mail'
6
+
7
+ describe ::Ditty::Emails::Base do
8
+ let(:mail) do
9
+ mail = Mail.new
10
+ allow(mail).to receive(:deliver!)
11
+ mail
12
+ end
13
+
14
+ describe '.new' do
15
+ it 'defaults to base options' do
16
+ expect(subject.options).to include subject: '(No Subject)', from: 'no-reply@ditty.io', view: :base
17
+ end
18
+
19
+ it 'allows the use of layouts' do
20
+ skip 'Test is not accurate. The class no longer uses body.'
21
+ base = described_class.new(layout: 'action', mail: mail)
22
+ expect(mail).to receive(:body).with(/^<!DOCTYPE html>/m)
23
+ base.deliver!('test@email.com')
24
+ end
25
+ end
26
+
27
+ describe '.deliver!' do
28
+ it 'delivers the email to the specified email address' do
29
+ expect(mail).to receive(:to).with('test@email.com')
30
+ expect(mail).to receive(:deliver!)
31
+ described_class.deliver!('test@email.com', mail: mail)
32
+ end
33
+
34
+ it 'passes down local variables' do
35
+ skip 'Test is not accurate. The class no longer uses body.'
36
+ expect(mail).to receive(:body).with("test content\n")
37
+ described_class.deliver!('test@email.com', locals: { content: 'test content' }, mail: mail)
38
+ end
39
+
40
+ it 'sets the email\'s subject and from address' do
41
+ expect(mail).to receive(:subject).with('test subject')
42
+ expect(mail).to receive(:from).with('from@test.com')
43
+ described_class.deliver!('test@email.com', subject: 'test subject', from: 'from@test.com', mail: mail)
44
+ end
45
+ end
46
+
47
+ describe '#deliver!' do
48
+ it 'delivers the email to the specified email address' do
49
+ expect(mail).to receive(:to).with('test2@email.com')
50
+ base = described_class.new(mail: mail)
51
+ base.deliver!('test2@email.com')
52
+ end
53
+
54
+ it 'passes the local variables to the template' do
55
+ skip 'Test is not accurate. The class no longer uses body.'
56
+ expect(mail).to receive(:body).with("test content\n")
57
+ base = described_class.new(mail: mail)
58
+ base.deliver!('test@email.com', content: 'test content')
59
+ end
60
+
61
+ it 'sets the email\'s subject and from address' do
62
+ expect(mail).to receive(:subject).with('test subject')
63
+ expect(mail).to receive(:from).with('from@test.com')
64
+ base = described_class.new(subject: 'test subject', from: 'from@test.com', mail: mail)
65
+ base.deliver!('test@email.com')
66
+ end
67
+ end
68
+
69
+ context 'method_missing' do
70
+ it 'passes unknown message to the underlying mail object' do
71
+ expect(mail).to receive(:cc).with('cc@test.com')
72
+ base = described_class.new(mail: mail)
73
+ base.cc 'cc@test.com'
74
+ end
75
+ end
76
+ end