ditty 0.7.1 → 0.10.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.
Files changed (185) 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 +24 -8
  6. data/.travis.yml +4 -8
  7. data/CNAME +1 -0
  8. data/Dockerfile +18 -0
  9. data/Gemfile.ci +0 -15
  10. data/Rakefile +5 -4
  11. data/Readme.md +24 -2
  12. data/_config.yml +1 -0
  13. data/config.ru +4 -4
  14. data/ditty.gemspec +31 -20
  15. data/docs/CNAME +1 -0
  16. data/docs/_config.yml +1 -0
  17. data/docs/index.md +34 -0
  18. data/exe/ditty +2 -0
  19. data/lib/ditty.rb +30 -4
  20. data/lib/ditty/cli.rb +38 -5
  21. data/lib/ditty/components/ditty.rb +82 -0
  22. data/lib/ditty/controllers/application_controller.rb +267 -0
  23. data/lib/ditty/controllers/{audit_logs.rb → audit_logs_controller.rb} +5 -7
  24. data/lib/ditty/controllers/{auth.rb → auth_controller.rb} +56 -32
  25. data/lib/ditty/controllers/{component.rb → component_controller.rb} +35 -24
  26. data/lib/ditty/controllers/{main.rb → main_controller.rb} +7 -7
  27. data/lib/ditty/controllers/roles_controller.rb +23 -0
  28. data/lib/ditty/controllers/user_login_traits_controller.rb +46 -0
  29. data/lib/ditty/controllers/{users.rb → users_controller.rb} +17 -20
  30. data/lib/ditty/db.rb +9 -5
  31. data/lib/ditty/emails/base.rb +48 -34
  32. data/lib/ditty/generators/crud_generator.rb +114 -0
  33. data/lib/ditty/generators/migration_generator.rb +26 -0
  34. data/lib/ditty/generators/project_generator.rb +52 -0
  35. data/lib/ditty/helpers/authentication.rb +6 -5
  36. data/lib/ditty/helpers/component.rb +11 -2
  37. data/lib/ditty/helpers/pundit.rb +24 -8
  38. data/lib/ditty/helpers/response.rb +38 -15
  39. data/lib/ditty/helpers/views.rb +48 -6
  40. data/lib/ditty/listener.rb +44 -14
  41. data/lib/ditty/memcached.rb +8 -0
  42. data/lib/ditty/middleware/accept_extension.rb +4 -2
  43. data/lib/ditty/middleware/error_catchall.rb +4 -2
  44. data/lib/ditty/models/audit_log.rb +1 -0
  45. data/lib/ditty/models/base.rb +13 -0
  46. data/lib/ditty/models/identity.rb +10 -7
  47. data/lib/ditty/models/role.rb +2 -0
  48. data/lib/ditty/models/user.rb +40 -3
  49. data/lib/ditty/models/user_login_trait.rb +17 -0
  50. data/lib/ditty/policies/audit_log_policy.rb +6 -6
  51. data/lib/ditty/policies/role_policy.rb +3 -3
  52. data/lib/ditty/policies/user_login_trait_policy.rb +45 -0
  53. data/lib/ditty/policies/user_policy.rb +3 -3
  54. data/lib/ditty/rubocop.rb +3 -0
  55. data/lib/ditty/seed.rb +2 -0
  56. data/lib/ditty/services/authentication.rb +31 -15
  57. data/lib/ditty/services/email.rb +22 -12
  58. data/lib/ditty/services/logger.rb +30 -13
  59. data/lib/ditty/services/pagination_wrapper.rb +9 -5
  60. data/lib/ditty/services/settings.rb +19 -7
  61. data/lib/ditty/tasks/ditty.rake +127 -0
  62. data/lib/ditty/tasks/omniauth-ldap.rake +43 -0
  63. data/lib/ditty/templates/.gitignore +5 -0
  64. data/lib/ditty/templates/.rspec +2 -0
  65. data/lib/ditty/templates/.rubocop.yml +7 -0
  66. data/lib/ditty/templates/Rakefile +12 -0
  67. data/lib/ditty/templates/application.rb +12 -0
  68. data/lib/ditty/templates/config.ru +37 -0
  69. data/lib/ditty/templates/controller.rb.erb +64 -0
  70. data/lib/ditty/templates/env.example +4 -0
  71. data/lib/ditty/templates/lib/project.rb.erb +5 -0
  72. data/lib/ditty/templates/migration.rb.erb +7 -0
  73. data/lib/ditty/templates/model.rb.erb +26 -0
  74. data/lib/ditty/templates/pids/.empty_directory +0 -0
  75. data/lib/ditty/templates/policy.rb.erb +48 -0
  76. data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
  77. data/lib/ditty/templates/public/css/sb-admin-2.min.css +10 -0
  78. data/lib/ditty/templates/public/css/styles.css +13 -0
  79. data/lib/ditty/templates/public/favicon.ico +0 -0
  80. data/{public → lib/ditty/templates/public}/images/apple-icon.png +0 -0
  81. data/{public → lib/ditty/templates/public}/images/favicon-16x16.png +0 -0
  82. data/{public → lib/ditty/templates/public}/images/favicon-32x32.png +0 -0
  83. data/{public → lib/ditty/templates/public}/images/launcher-icon-1x.png +0 -0
  84. data/{public → lib/ditty/templates/public}/images/launcher-icon-2x.png +0 -0
  85. data/{public → lib/ditty/templates/public}/images/launcher-icon-4x.png +0 -0
  86. data/{public → lib/ditty/templates/public}/images/mstile-150x150.png +0 -0
  87. data/{public → lib/ditty/templates/public}/images/safari-pinned-tab.svg +0 -0
  88. data/lib/ditty/templates/public/js/sb-admin-2.min.js +7 -0
  89. data/lib/ditty/templates/public/js/scripts.js +1 -0
  90. data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
  91. data/lib/ditty/templates/settings.yml.erb +19 -0
  92. data/lib/ditty/templates/sidekiq.rb +18 -0
  93. data/lib/ditty/templates/sidekiq.yml +9 -0
  94. data/lib/ditty/templates/spec_helper.rb +43 -0
  95. data/lib/ditty/templates/type.rb.erb +21 -0
  96. data/lib/ditty/templates/views/display.haml.tt +20 -0
  97. data/lib/ditty/templates/views/edit.haml.tt +10 -0
  98. data/lib/ditty/templates/views/form.haml.tt +11 -0
  99. data/lib/ditty/templates/views/index.haml.tt +29 -0
  100. data/lib/ditty/templates/views/new.haml.tt +10 -0
  101. data/lib/ditty/version.rb +1 -1
  102. data/lib/rubocop/cop/ditty/call_services_directly.rb +42 -0
  103. data/migrate/20181209_add_user_login_traits.rb +16 -0
  104. data/migrate/20181209_extend_audit_log.rb +12 -0
  105. data/migrate/20190220_add_parent_id_to_roles.rb +9 -0
  106. data/spec/ditty/api_spec.rb +51 -0
  107. data/spec/ditty/controllers/roles_spec.rb +67 -0
  108. data/spec/ditty/controllers/user_login_traits_spec.rb +72 -0
  109. data/spec/ditty/controllers/users_spec.rb +72 -0
  110. data/spec/ditty/emails/base_spec.rb +76 -0
  111. data/spec/ditty/emails/forgot_password_spec.rb +20 -0
  112. data/spec/ditty/helpers/component_spec.rb +85 -0
  113. data/spec/ditty/models/user_spec.rb +36 -0
  114. data/spec/ditty/services/email_spec.rb +36 -0
  115. data/spec/ditty/services/logger_spec.rb +68 -0
  116. data/spec/ditty/services/settings_spec.rb +63 -0
  117. data/spec/ditty_spec.rb +9 -0
  118. data/spec/factories.rb +46 -0
  119. data/spec/fixtures/logger.yml +17 -0
  120. data/spec/fixtures/section.yml +3 -0
  121. data/spec/fixtures/settings.yml +8 -0
  122. data/spec/spec_helper.rb +51 -0
  123. data/spec/support/api_shared_examples.rb +250 -0
  124. data/spec/support/crud_shared_examples.rb +145 -0
  125. data/views/403.haml +2 -0
  126. data/views/404.haml +2 -4
  127. data/views/500.haml +11 -0
  128. data/views/audit_logs/index.haml +32 -28
  129. data/views/auth/forgot_password.haml +32 -16
  130. data/views/auth/identity.haml +14 -13
  131. data/views/auth/ldap.haml +17 -0
  132. data/views/auth/login.haml +23 -17
  133. data/views/auth/register.haml +20 -18
  134. data/views/auth/register_identity.haml +27 -12
  135. data/views/auth/reset_password.haml +36 -19
  136. data/views/blank.haml +43 -0
  137. data/views/emails/forgot_password.haml +1 -1
  138. data/views/emails/layouts/action.haml +10 -6
  139. data/views/emails/layouts/alert.haml +2 -1
  140. data/views/emails/layouts/billing.haml +2 -1
  141. data/views/embedded.haml +17 -11
  142. data/views/error.haml +8 -3
  143. data/views/index.haml +1 -1
  144. data/views/layout.haml +45 -30
  145. data/views/partials/actions.haml +15 -14
  146. data/views/partials/content_tag.haml +0 -0
  147. data/views/partials/delete_form.haml +1 -1
  148. data/views/partials/filter_control.haml +2 -2
  149. data/views/partials/footer.haml +13 -5
  150. data/views/partials/form_control.haml +30 -19
  151. data/views/partials/form_tag.haml +1 -1
  152. data/views/partials/navitems.haml +42 -0
  153. data/views/partials/notifications.haml +12 -8
  154. data/views/partials/pager.haml +44 -25
  155. data/views/partials/search.haml +15 -11
  156. data/views/partials/sidebar.haml +15 -37
  157. data/views/partials/sort_ui.haml +2 -0
  158. data/views/partials/timespan_selector.haml +64 -0
  159. data/views/partials/topbar.haml +53 -0
  160. data/views/partials/user_associations.haml +32 -0
  161. data/views/quick_start.haml +23 -0
  162. data/views/roles/display.haml +27 -6
  163. data/views/roles/edit.haml +3 -3
  164. data/views/roles/form.haml +1 -0
  165. data/views/roles/index.haml +23 -14
  166. data/views/roles/new.haml +2 -2
  167. data/views/user_login_traits/display.haml +32 -0
  168. data/views/user_login_traits/edit.haml +10 -0
  169. data/views/user_login_traits/form.haml +5 -0
  170. data/views/user_login_traits/index.haml +28 -0
  171. data/views/user_login_traits/new.haml +10 -0
  172. data/views/users/display.haml +15 -16
  173. data/views/users/edit.haml +3 -3
  174. data/views/users/form.haml +0 -0
  175. data/views/users/index.haml +31 -24
  176. data/views/users/login_traits.haml +25 -0
  177. data/views/users/new.haml +2 -2
  178. data/views/users/profile.haml +17 -15
  179. data/views/users/user.haml +1 -1
  180. metadata +314 -76
  181. data/lib/ditty/components/app.rb +0 -77
  182. data/lib/ditty/controllers/application.rb +0 -175
  183. data/lib/ditty/controllers/roles.rb +0 -16
  184. data/lib/ditty/rake_tasks.rb +0 -102
  185. data/views/partials/navbar.haml +0 -23
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.7.1'.freeze
4
+ VERSION = '0.10.1'
5
5
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+ require 'rubocop/ast/node'
5
+ require 'rubocop/cop/cop'
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module Ditty
10
+ # This cop enforces the use of `Service.method` instead of
11
+ # `Service.instance.method`. Calling the singleton instance has been
12
+ # deprecated for services.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # ::Ditty::Services::Logger.instance.info 'This is a log message'
17
+ #
18
+ # # good
19
+ # ::Ditty::Services::Logger.info 'This is a log message'
20
+ class CallServicesDirectly < RuboCop::Cop::Cop
21
+ MSG = 'Do not use `.instance` on services. Call the method directly instead'
22
+
23
+ def_node_matcher :service_instance_call?, <<-PATTERN
24
+ (send (const (const (const ... :Ditty) :Services) _) :instance)
25
+ PATTERN
26
+
27
+ def on_send(node)
28
+ return unless service_instance_call?(node)
29
+
30
+ add_offense(node)
31
+ end
32
+
33
+ def autocorrect(node)
34
+ lambda do |corrector|
35
+ internal = node.children.first.source
36
+ corrector.replace(node.loc.expression, internal)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table :user_login_traits do
6
+ primary_key :id
7
+ foreign_key :user_id, :users
8
+ String :ip_address, null: true
9
+ String :platform, null: true
10
+ String :device, null: true
11
+ String :browser, null: true
12
+ DateTime :created_at
13
+ DateTime :updated_at
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ alter_table :audit_logs do
6
+ add_column :ip_address, String
7
+ add_column :platform, String
8
+ add_column :device, String
9
+ add_column :browser, String
10
+ end
11
+ end
12
+ 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
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ditty/emails/forgot_password'
5
+ require 'mail'
6
+
7
+ describe ::Ditty::Emails::ForgotPassword 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: 'Request to reset password', from: 'no-reply@ditty.io',
17
+ view: :forgot_password
18
+ end
19
+ end
20
+ end