pollett 0.1.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 (114) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +81 -0
  4. data/Rakefile +25 -0
  5. data/app/controllers/concerns/pollett/controller.rb +37 -0
  6. data/app/controllers/pollett/application_controller.rb +4 -0
  7. data/app/controllers/pollett/keys_controller.rb +5 -0
  8. data/app/controllers/pollett/sessions_controller.rb +5 -0
  9. data/app/controllers/pollett/users_controller.rb +5 -0
  10. data/app/mailers/pollett/mailer.rb +5 -0
  11. data/app/models/concerns/pollett/user.rb +40 -0
  12. data/app/models/pollett/context.rb +5 -0
  13. data/app/models/pollett/key.rb +5 -0
  14. data/app/models/pollett/session.rb +5 -0
  15. data/app/serializers/pollett/key_serializer.rb +5 -0
  16. data/app/serializers/pollett/session_serializer.rb +5 -0
  17. data/app/serializers/user_serializer.rb +3 -0
  18. data/app/services/pollett/authenticate_user.rb +5 -0
  19. data/app/services/pollett/change_password.rb +5 -0
  20. data/app/services/pollett/create_session.rb +5 -0
  21. data/app/services/pollett/register_user.rb +5 -0
  22. data/app/services/pollett/reset_password.rb +5 -0
  23. data/app/views/pollett/mailer/reset.text.erb +5 -0
  24. data/app/views/pollett/mailer/welcome.text.erb +1 -0
  25. data/config/locales/en.yml +14 -0
  26. data/config/routes.rb +11 -0
  27. data/db/migrate/20150226024506_create_pollett_contexts.rb +21 -0
  28. data/lib/generators/pollett/install/install_generator.rb +123 -0
  29. data/lib/generators/pollett/install/templates/db/migrate/add_pollett_to_users.rb +21 -0
  30. data/lib/generators/pollett/install/templates/db/migrate/create_users.rb +15 -0
  31. data/lib/generators/pollett/install/templates/initializer.rb +3 -0
  32. data/lib/generators/pollett/install/templates/user.rb +3 -0
  33. data/lib/pollett.rb +20 -0
  34. data/lib/pollett/concerns.rb +5 -0
  35. data/lib/pollett/concerns/controllers.rb +3 -0
  36. data/lib/pollett/concerns/controllers/keys_controller.rb +37 -0
  37. data/lib/pollett/concerns/controllers/sessions_controller.rb +43 -0
  38. data/lib/pollett/concerns/controllers/users_controller.rb +28 -0
  39. data/lib/pollett/concerns/mailers.rb +1 -0
  40. data/lib/pollett/concerns/mailers/mailer.rb +24 -0
  41. data/lib/pollett/concerns/models.rb +3 -0
  42. data/lib/pollett/concerns/models/context.rb +42 -0
  43. data/lib/pollett/concerns/models/key.rb +13 -0
  44. data/lib/pollett/concerns/models/session.rb +20 -0
  45. data/lib/pollett/concerns/serializers.rb +2 -0
  46. data/lib/pollett/concerns/serializers/context_serializer.rb +21 -0
  47. data/lib/pollett/concerns/serializers/user_serializer.rb +16 -0
  48. data/lib/pollett/concerns/services.rb +5 -0
  49. data/lib/pollett/concerns/services/authenticate_user.rb +21 -0
  50. data/lib/pollett/concerns/services/change_password.rb +21 -0
  51. data/lib/pollett/concerns/services/create_session.rb +27 -0
  52. data/lib/pollett/concerns/services/register_user.rb +29 -0
  53. data/lib/pollett/concerns/services/reset_password.rb +27 -0
  54. data/lib/pollett/configuration.rb +34 -0
  55. data/lib/pollett/engine.rb +12 -0
  56. data/lib/pollett/rspec.rb +6 -0
  57. data/lib/pollett/testing/request_helper.rb +106 -0
  58. data/lib/pollett/version.rb +3 -0
  59. data/spec/dummy/README.rdoc +28 -0
  60. data/spec/dummy/Rakefile +6 -0
  61. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  62. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  63. data/spec/dummy/app/controllers/application_controller.rb +12 -0
  64. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  65. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  66. data/spec/dummy/app/models/user.rb +3 -0
  67. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  68. data/spec/dummy/app/views/layouts/mailer.text.erb +6 -0
  69. data/spec/dummy/bin/bundle +3 -0
  70. data/spec/dummy/bin/rails +4 -0
  71. data/spec/dummy/bin/rake +4 -0
  72. data/spec/dummy/bin/setup +29 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/config/application.rb +32 -0
  75. data/spec/dummy/config/boot.rb +5 -0
  76. data/spec/dummy/config/database.yml +85 -0
  77. data/spec/dummy/config/environment.rb +5 -0
  78. data/spec/dummy/config/environments/development.rb +41 -0
  79. data/spec/dummy/config/environments/production.rb +79 -0
  80. data/spec/dummy/config/environments/test.rb +42 -0
  81. data/spec/dummy/config/initializers/active_model_serializers.rb +1 -0
  82. data/spec/dummy/config/initializers/assets.rb +11 -0
  83. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  84. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  85. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  86. data/spec/dummy/config/initializers/inflections.rb +16 -0
  87. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  88. data/spec/dummy/config/initializers/session_store.rb +3 -0
  89. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  90. data/spec/dummy/config/locales/en.yml +23 -0
  91. data/spec/dummy/config/routes.rb +3 -0
  92. data/spec/dummy/config/secrets.yml +22 -0
  93. data/spec/dummy/db/migrate/20150226030314_enable_uuid_extension.rb +5 -0
  94. data/spec/dummy/db/migrate/20150226030315_create_users.rb +15 -0
  95. data/spec/dummy/db/migrate/20150226030316_create_pollett_contexts.pollett.rb +22 -0
  96. data/spec/dummy/db/schema.rb +49 -0
  97. data/spec/dummy/log/development.log +1315 -0
  98. data/spec/dummy/log/test.log +181283 -0
  99. data/spec/dummy/public/404.html +67 -0
  100. data/spec/dummy/public/422.html +67 -0
  101. data/spec/dummy/public/500.html +66 -0
  102. data/spec/dummy/public/favicon.ico +0 -0
  103. data/spec/factories/pollett_context.rb +5 -0
  104. data/spec/factories/pollett_key.rb +5 -0
  105. data/spec/factories/pollett_session.rb +5 -0
  106. data/spec/factories/user.rb +7 -0
  107. data/spec/mailers/pollett/mailer_spec.rb +73 -0
  108. data/spec/rails_helper.rb +19 -0
  109. data/spec/requests/keys_spec.rb +67 -0
  110. data/spec/requests/sessions_spec.rb +176 -0
  111. data/spec/requests/user_spec.rb +41 -0
  112. data/spec/spec_helper.rb +9 -0
  113. data/spec/support/email_helper.rb +9 -0
  114. metadata +323 -0
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :pollett_context, class: Pollett::Context do
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :pollett_key, parent: :pollett_context, class: Pollett::Key do
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :pollett_session, parent: :pollett_context, class: Pollett::Session do
3
+ accessed_at { Time.now.utc }
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ sequence(:name) { |n| "User #{n}" }
4
+ sequence(:email) { |n| "user.#{n}@example.com" }
5
+ password "password"
6
+ end
7
+ end
@@ -0,0 +1,73 @@
1
+ require "rails_helper"
2
+
3
+ module Pollett
4
+ describe Mailer do
5
+ let!(:user) { create(:user, email: "john@example.com") }
6
+
7
+ describe ".welcome" do
8
+ let(:mail) { Mailer.welcome(user) }
9
+
10
+ it "sends email" do
11
+ mail.deliver_now
12
+
13
+ expect(last_email).to be_present
14
+ end
15
+
16
+ it "sets fields correctly" do
17
+ email = mail.deliver_now
18
+
19
+ expect(email[:from].decoded).to eq("from@example.com")
20
+ expect(email[:to].decoded).to eq("john@example.com")
21
+ expect(email.subject).to eq("Welcome!")
22
+ end
23
+
24
+ it "renders body correctly" do
25
+ body = mail.deliver_now.body.to_s
26
+
27
+ expect(body).to include("Welcome aboard!")
28
+ end
29
+
30
+ it "renders layout correctly" do
31
+ body = mail.deliver_now.body.to_s
32
+
33
+ expect(body).to include("Hi there")
34
+ expect(body).to include("Pollett Team")
35
+ end
36
+ end
37
+
38
+ describe ".reset" do
39
+ before { user.update!(reset_token: Pollett.generate_token) }
40
+
41
+ let(:mail) { Mailer.reset(user) }
42
+
43
+ it "sends email" do
44
+ mail.deliver_now
45
+
46
+ expect(last_email).to be_present
47
+ end
48
+
49
+ it "sets fields correctly" do
50
+ email = mail.deliver_now
51
+
52
+ expect(email[:from].decoded).to eq("from@example.com")
53
+ expect(email[:to].decoded).to eq("john@example.com")
54
+ expect(email.subject).to eq("Password Reset")
55
+ end
56
+
57
+ it "renders body correctly" do
58
+ body = mail.deliver_now.body.to_s
59
+
60
+ expect(body).to include("password change")
61
+ expect(body).to include("/#{user.reset_token}/reset")
62
+ expect(body).to include("ignore this email")
63
+ end
64
+
65
+ it "renders layout correctly" do
66
+ body = mail.deliver_now.body.to_s
67
+
68
+ expect(body).to include("Hi there")
69
+ expect(body).to include("Pollett Team")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,19 @@
1
+ ENV["RAILS_ENV"] ||= "test"
2
+ require "spec_helper"
3
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
4
+ require "rspec/rails"
5
+ require "factory_girl_rails"
6
+ require "pollett/rspec"
7
+
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
9
+
10
+ RSpec.configure do |config|
11
+ config.include FactoryGirl::Syntax::Methods
12
+ config.include EmailHelper
13
+
14
+ config.infer_spec_type_from_file_location!
15
+ config.use_transactional_fixtures = true
16
+ config.order = :random
17
+
18
+ config.before(:each) { reset_email }
19
+ end
@@ -0,0 +1,67 @@
1
+ require "rails_helper"
2
+
3
+ describe "Keys" do
4
+ let!(:user) { create(:user, email: "john@example.com", password: "password") }
5
+ let!(:session) { create(:pollett_session, user: user) }
6
+ let!(:active) { create(:pollett_key, user: user, client: "active") }
7
+
8
+ describe "GET /keys" do
9
+ let!(:inactive) { create(:pollett_key, user: user, revoked_at: 1.day.ago, client: "inactive") }
10
+
11
+ it_requires_authentication(:get, "/keys")
12
+
13
+ it "responds with all active keys" do
14
+ a_get("/keys", session)
15
+
16
+ expect(data.map { |k| k[:id] }).to eq([active.id])
17
+ expect_status(200)
18
+ end
19
+ end
20
+
21
+ describe "POST /keys" do
22
+ it_requires_authentication(:post, "/keys")
23
+
24
+ context "with valid params" do
25
+ let(:params) { { client: "fake" } }
26
+
27
+ it "responds with new key" do
28
+ a_post("/keys", session, params)
29
+
30
+ expect(data[:relationships][:user][:data][:id]).to eq(user.id)
31
+ expect(data[:attributes][:client]).to eq("fake")
32
+ expect_status(201)
33
+ end
34
+ end
35
+
36
+ context "with invalid params" do
37
+ let(:params) { { } }
38
+
39
+ it "raises an invalid record error" do
40
+ expect do
41
+ a_post("/keys", session, params)
42
+ end.to raise_error(ActiveRecord::RecordInvalid)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "GET /keys/:id" do
48
+ it_requires_authentication(:get, "/keys/1")
49
+
50
+ it "responds with the specified key" do
51
+ a_get("/keys/#{active.id}", session)
52
+
53
+ expect(data[:id]).to eq(active.id)
54
+ expect_status(200)
55
+ end
56
+ end
57
+
58
+ describe "DELETE /keys/:id" do
59
+ it_requires_authentication(:delete, "/keys/:id")
60
+
61
+ it "responds with nothing" do
62
+ a_delete("/keys/#{active.id}", session)
63
+
64
+ expect_status(204)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,176 @@
1
+ require "rails_helper"
2
+
3
+ describe "Sessions" do
4
+ let!(:user) { create(:user, email: "john@example.com", password: "password") }
5
+ let!(:session) { create(:pollett_session, user: user) }
6
+
7
+ describe "GET /sessions" do
8
+ let!(:inactive) { create(:pollett_session, user: user, revoked_at: 1.day.ago) }
9
+
10
+ it_requires_authentication(:get, "/sessions")
11
+
12
+ it "responds with all active sessions" do
13
+ a_get("/sessions", session)
14
+
15
+ expect(data.map { |s| s[:id] }).to eq([session.id])
16
+ expect_status(200)
17
+ end
18
+ end
19
+
20
+ describe "GET /sessions/:id" do
21
+ it_requires_authentication(:get, "/sessions/1")
22
+
23
+ it "responds with the specified session" do
24
+ a_get("/sessions/#{session.id}", session)
25
+
26
+ expect(data[:id]).to eq(session.id)
27
+ expect_status(200)
28
+ end
29
+ end
30
+
31
+ describe "POST /sessions" do
32
+ context "when logging in" do
33
+ let(:params) { { email: "john@example.com", password: "password" } }
34
+
35
+ context "with valid credentials" do
36
+ it "responds with new session" do
37
+ json_request(:post, "/sessions", params)
38
+
39
+ expect(data[:relationships][:user][:data][:id]).to eq(user.id)
40
+ expect_status(201)
41
+ end
42
+ end
43
+
44
+ context "with invalid credentials" do
45
+ before { params[:password] = "wrong" }
46
+
47
+ it "raises an unauthorized error" do
48
+ expect do
49
+ json_request(:post, "/sessions", params)
50
+ end.to raise_error(Pollett::Unauthorized)
51
+ end
52
+ end
53
+ end
54
+
55
+ context "when registering" do
56
+ let(:params) { { name: "New User", email: "new@example.com", password: "password" } }
57
+
58
+ context "with valid params" do
59
+ it "responds with new session" do
60
+ json_request(:post, "/sessions", params)
61
+
62
+ expect(data[:relationships][:user][:data][:id]).to be_a(String)
63
+ expect_status(201)
64
+ end
65
+
66
+ it "sends a welcome email" do
67
+ json_request(:post, "/sessions", params)
68
+
69
+ expect(last_email).to be_present
70
+ expect(last_email.to).to include("new@example.com")
71
+ end
72
+
73
+ context "and config.send_welcome_email set to false" do
74
+ before { Pollett.config.send_welcome_email = false }
75
+
76
+ it "does not send a welcome email" do
77
+ json_request(:post, "/sessions", params)
78
+
79
+ expect(last_email).to be_nil
80
+ end
81
+ end
82
+ end
83
+
84
+ context "with invalid params" do
85
+ before { params.delete(:email) }
86
+
87
+ it "raises an invalid record error" do
88
+ expect do
89
+ json_request(:post, "/sessions", params)
90
+ end.to raise_error(ActiveRecord::RecordInvalid)
91
+ end
92
+ end
93
+ end
94
+
95
+ context "when resetting password" do
96
+ before { user.update!(reset_token: Pollett.generate_token) }
97
+
98
+ let(:params) { { token: user.reset_token, password: "password" } }
99
+
100
+ context "with valid params" do
101
+ it "responds with new session" do
102
+ json_request(:post, "/sessions", params)
103
+
104
+ expect(data[:relationships][:user][:data][:id]).to eq(user.id)
105
+ expect_status(201)
106
+ end
107
+ end
108
+
109
+ context "with invalid password" do
110
+ before { params[:password] = "wrong" }
111
+
112
+ it "raises an invalid record error" do
113
+ expect do
114
+ json_request(:post, "/sessions", params)
115
+ end.to raise_error(ActiveRecord::RecordInvalid)
116
+ end
117
+ end
118
+
119
+ context "with invalid reset_token" do
120
+ before { params[:token] = "wrong" }
121
+
122
+ it "raises a record not found error" do
123
+ expect do
124
+ json_request(:post, "/sessions", params)
125
+ end.to raise_error(ActiveRecord::RecordNotFound)
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ describe "POST /sessions/forgot" do
132
+ context "when email is valid" do
133
+ let(:params) { { email: "john@example.com" } }
134
+
135
+ it "is accepted" do
136
+ json_request(:post, "/sessions/forgot", params)
137
+
138
+ expect_status(202)
139
+ end
140
+
141
+ it "sends an email" do
142
+ json_request(:post, "/sessions/forgot", params)
143
+
144
+ expect(last_email).to be_present
145
+ expect(last_email.to).to include("john@example.com")
146
+ expect(last_email.body.to_s).to match(/\w+\/reset/)
147
+ end
148
+ end
149
+
150
+ context "when email is invalid" do
151
+ let(:params) { { email: "wrong@example.com" } }
152
+
153
+ it "is accepted" do
154
+ json_request(:post, "/sessions/forgot", params)
155
+
156
+ expect_status(202)
157
+ end
158
+
159
+ it "does not send an email" do
160
+ json_request(:post, "/sessions/forgot", params)
161
+
162
+ expect(last_email).to be_nil
163
+ end
164
+ end
165
+ end
166
+
167
+ describe "DELETE /sessions/:id" do
168
+ it_requires_authentication(:delete, "/sessions/1")
169
+
170
+ it "responds with nothing" do
171
+ a_delete("/sessions/#{session.id}", session)
172
+
173
+ expect_status(204)
174
+ end
175
+ end
176
+ end