trek 2.5.0 → 2.6.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.
- checksums.yaml +4 -4
- data/.node-version +1 -1
- data/AGENTS.md +7 -4
- data/CHANGELOG.md +37 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +16 -3
- data/Makefile +2 -0
- data/app/components/trek/dashboard/tile_component/tile_component.css +9 -0
- data/app/components/trek/dashboard/tile_component/tile_component.html.slim +4 -2
- data/app/components/trek/dashboard/tile_component.rb +12 -2
- data/app/components/trek/form/content_editor_component/content_editor_component.css +5 -0
- data/app/components/trek/form/content_editor_component/content_editor_component.html.slim +19 -93
- data/app/components/trek/form/content_editor_component/content_editor_component.js +94 -251
- data/app/components/trek/form/content_editor_component/extensions/block_view.js +40 -0
- data/app/components/trek/form/content_editor_component/extensions/image_block.js +28 -26
- data/app/components/trek/form/content_editor_component/extensions/prompts_block.js +15 -26
- data/app/components/trek/form/content_editor_component/extensions/table_of_contents.js +1 -3
- data/app/components/trek/form/content_editor_component.rb +15 -0
- data/app/components/trek/form/image_field_component/image_field_component.css +40 -1
- data/app/components/trek/form/image_field_component/image_field_component.html.slim +0 -9
- data/app/components/trek/form/image_field_component.rb +36 -9
- data/app/content/trek/content/cleaner.rb +53 -0
- data/app/content/trek/content/document.rb +2 -2
- data/app/content/trek/content/prompts_block.rb +1 -2
- data/app/content/trek/content.rb +6 -0
- data/app/controllers/concerns/trek/reorderable.rb +24 -6
- data/app/controllers/trek/csp_reports_controller.rb +14 -1
- data/app/controllers/trek/panels/prompts_controller.rb +1 -1
- data/app/controllers/trek/resource_controller.rb +5 -5
- data/app/jobs/trek/purge_expired_sessions_job.rb +4 -3
- data/app/models/concerns/trek/contentable.rb +15 -1
- data/app/models/concerns/trek/users/sign_in_code.rb +70 -0
- data/app/models/concerns/trek/users/sign_in_lockout.rb +4 -2
- data/app/views/trek/panels/links/_form.html.slim +2 -4
- data/app/views/trek/panels/prompts/create.turbo_stream.slim +0 -1
- data/config/locales/trek.en.yml +26 -11
- data/config/locales/trek.fr.yml +26 -11
- data/docs/.vitepress/config.mjs +4 -1
- data/docs/background-jobs.md +69 -0
- data/docs/content-editor.md +219 -0
- data/docs/customize.md +2 -0
- data/docs/deploy.md +2 -2
- data/docs/getting-started.md +1 -1
- data/docs/index.md +1 -1
- data/docs/reference/components.md +2 -2
- data/docs/reference/concerns/contentable.md +10 -4
- data/docs/reference/concerns/formattable.md +1 -1
- data/docs/reference/environment-variables.md +1 -0
- data/docs/reference/formatters.md +2 -30
- data/docs/reference/forms.md +1 -1
- data/docs/reference/generators/audit-log.md +2 -2
- data/docs/reference/generators/install.md +3 -2
- data/docs/reference/generators/public-accounts.md +141 -0
- data/docs/reference/generators/security-headers.md +1 -1
- data/docs/reference/index.md +2 -1
- data/docs/reference/models/user.md +3 -1
- data/docs/what-is-trek.md +1 -1
- data/lib/generators/trek/audit_log_generator.rb +54 -0
- data/lib/generators/trek/install/admin/users_generator.rb +6 -1
- data/lib/generators/trek/install/audit_log_generator.rb +9 -45
- data/lib/generators/trek/install/good_job_generator.rb +161 -0
- data/lib/generators/trek/install/model_specs_generator.rb +3 -3
- data/lib/generators/trek/install/ruby_generator.rb +1 -1
- data/lib/generators/trek/install/scalingo_generator.rb +7 -45
- data/lib/generators/trek/install_generator.rb +15 -0
- data/lib/generators/trek/public_accounts_generator.rb +267 -0
- data/lib/generators/trek/scalingo_generator.rb +55 -0
- data/lib/generators/trek/templates/.gitlab-ci.yml +1 -1
- data/lib/generators/trek/templates/controllers/admin/password_renewals_controller.rb +11 -0
- data/lib/generators/trek/templates/controllers/admin/user_sessions_controller.rb +1 -1
- data/lib/generators/trek/templates/controllers/admin/users_controller.rb +0 -8
- data/lib/generators/trek/templates/initializers/content_security_policy.rb +3 -2
- data/lib/generators/trek/templates/initializers/good_job.rb.tt +38 -0
- data/lib/generators/trek/templates/jobs/mail_delivery_job.rb +6 -0
- data/lib/generators/trek/templates/layouts/admin.html.slim +5 -0
- data/lib/generators/trek/templates/mailers/admin_mailer.rb +4 -2
- data/lib/generators/trek/templates/package.json.tt +1 -1
- data/lib/generators/trek/templates/public_accounts/api/authentication.rb.tt +76 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/accounts_controller.rb.tt +22 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/active_sessions_controller.rb.tt +21 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/base_controller.rb.tt +71 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/email_changes_controller.rb.tt +55 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/email_confirmations_controller.rb.tt +19 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/password_resets_controller.rb.tt +28 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/passwords_controller.rb.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/registrations_controller.rb.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/sessions_controller.rb.tt +45 -0
- data/lib/generators/trek/templates/public_accounts/api/controllers/sign_in_codes_controller.rb.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/jobs/sign_in_code_job.rb.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/locales/accounts.en.yml.tt +205 -0
- data/lib/generators/trek/templates/public_accounts/locales/accounts.fr.yml.tt +205 -0
- data/lib/generators/trek/templates/public_accounts/mailers/account_mailer.rb.tt +85 -0
- data/lib/generators/trek/templates/public_accounts/migrations/create_accounts.rb.tt +46 -0
- data/lib/generators/trek/templates/public_accounts/models/account/session.rb.tt +47 -0
- data/lib/generators/trek/templates/public_accounts/models/account/sign_in_code.rb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/models/account.rb.tt +73 -0
- data/lib/generators/trek/templates/public_accounts/spec/api/accounts_spec.rb.tt +90 -0
- data/lib/generators/trek/templates/public_accounts/spec/api/sign_ins_spec.rb.tt +158 -0
- data/lib/generators/trek/templates/public_accounts/spec/models/account/sign_in_code_spec.rb.tt +56 -0
- data/lib/generators/trek/templates/public_accounts/spec/models/account_spec.rb.tt +109 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/accounts_spec.rb.tt +126 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/authentication_spec.rb.tt +43 -0
- data/lib/generators/trek/templates/public_accounts/spec/web/sign_ins_spec.rb.tt +215 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.fr.html.slim.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.html.slim.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.fr.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.en.html.slim.tt +10 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.en.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.fr.html.slim.tt +13 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.fr.text.erb.tt +8 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.en.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.en.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.fr.html.slim.tt +9 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_code.fr.text.erb.tt +11 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.en.html.slim.tt +23 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.en.text.erb.tt +14 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.fr.html.slim.tt +24 -0
- data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.fr.text.erb.tt +14 -0
- data/lib/generators/trek/templates/public_accounts/web/authentication.rb.tt +97 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/accounts_controller.rb.tt +33 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/active_sessions_controller.rb.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/base_controller.rb.tt +52 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/email_changes_controller.rb.tt +85 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/email_confirmations_controller.rb.tt +19 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/password_resets_controller.rb.tt +41 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/passwords_controller.rb.tt +23 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/registrations_controller.rb.tt +24 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/sessions_controller.rb.tt +78 -0
- data/lib/generators/trek/templates/public_accounts/web/controllers/sign_in_codes_controller.rb.tt +27 -0
- data/lib/generators/trek/templates/public_accounts/web/views/_flash.html.slim.tt +5 -0
- data/lib/generators/trek/templates/public_accounts/web/views/accounts/show.html.slim.tt +52 -0
- data/lib/generators/trek/templates/public_accounts/web/views/email_changes/edit.html.slim.tt +17 -0
- data/lib/generators/trek/templates/public_accounts/web/views/email_changes/new.html.slim.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/views/password_resets/edit.html.slim.tt +26 -0
- data/lib/generators/trek/templates/public_accounts/web/views/password_resets/new.html.slim.tt +15 -0
- data/lib/generators/trek/templates/public_accounts/web/views/passwords/edit.html.slim.tt +25 -0
- data/lib/generators/trek/templates/public_accounts/web/views/registrations/new.html.slim.tt +28 -0
- data/lib/generators/trek/templates/public_accounts/web/views/sessions/new.html.slim.tt +38 -0
- data/lib/generators/trek/templates/public_accounts/web/views/sign_in_codes/new.html.slim.tt +17 -0
- data/lib/generators/trek/templates/spec/jobs/mail_delivery_job_spec.rb +11 -0
- data/lib/generators/trek/templates/spec/mailers/admin_mailer_spec.rb +10 -0
- data/lib/generators/trek/templates/spec/requests/admin/fragments_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/good_job_spec.rb +34 -0
- data/lib/generators/trek/templates/spec/requests/admin/pages_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/panels_spec.rb +16 -0
- data/lib/generators/trek/templates/spec/requests/admin/password_renewal_spec.rb +2 -2
- data/lib/generators/trek/templates/spec/requests/admin/sign_in_lockout_spec.rb +1 -1
- data/lib/generators/trek/templates/spec/requests/admin/user_sessions_spec.rb +2 -2
- data/lib/generators/trek/templates/views/admin/users/index.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.en.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.en.text.erb +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.fr.html.slim +1 -1
- data/lib/generators/trek/templates/views/admin_mailer/new_sign_in.fr.text.erb +1 -1
- data/lib/trek/csp_reports.rb +22 -4
- data/lib/trek/typography_formatter.rb +35 -4
- data/lib/trek/version.rb +1 -1
- data/package.json +12 -8
- data/trek.gemspec +1 -1
- data/vitest.config.mjs +24 -0
- data/yarn.lock +1004 -288
- metadata +90 -3
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require "rails_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "<%= human_name.pluralize %>' accounts", type: :request do
|
|
4
|
+
include ActiveSupport::Testing::TimeHelpers
|
|
5
|
+
|
|
6
|
+
<% if code? -%>
|
|
7
|
+
let(:<%= file_name %>) { <%= class_name %>.create!(email: "ada@example.com") }
|
|
8
|
+
|
|
9
|
+
def emailed_code
|
|
10
|
+
ActionMailer::Base.deliveries.last.text_part.body.to_s[/\b\d{6}\b/]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def change_email_to(email)
|
|
14
|
+
perform_enqueued_jobs { post <%= route_prefix %>_email_change_path, params: { email: } }
|
|
15
|
+
patch <%= route_prefix %>_email_change_path, params: { otp: emailed_code }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sign_in_as(<%= file_name %>)
|
|
19
|
+
perform_enqueued_jobs { post <%= route_prefix %>_sign_in_path, params: { email: <%= file_name %>.email } }
|
|
20
|
+
post <%= route_prefix %>_sign_in_code_path, params: { otp: emailed_code }
|
|
21
|
+
end
|
|
22
|
+
<% else -%>
|
|
23
|
+
let(:<%= file_name %>) { <%= class_name %>.create!(email: "ada@example.com", password: "correct horse battery staple") }
|
|
24
|
+
|
|
25
|
+
def emailed_link
|
|
26
|
+
ActionMailer::Base.deliveries.last.text_part.body.to_s[%r{https?://\S+}]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def change_email_to(email)
|
|
30
|
+
perform_enqueued_jobs { post <%= route_prefix %>_email_change_path, params: { email: } }
|
|
31
|
+
get emailed_link
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def sign_in_as(<%= file_name %>)
|
|
35
|
+
post <%= route_prefix %>_sign_in_path, params: { email: <%= file_name %>.email, password: "correct horse battery staple" }
|
|
36
|
+
end
|
|
37
|
+
<% end -%>
|
|
38
|
+
|
|
39
|
+
it "asks to sign in" do
|
|
40
|
+
get <%= route_prefix %>_account_path
|
|
41
|
+
|
|
42
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "shows the account" do
|
|
46
|
+
sign_in_as(<%= file_name %>)
|
|
47
|
+
get <%= route_prefix %>_account_path
|
|
48
|
+
|
|
49
|
+
expect(response.body).to include(<%= file_name %>.email)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "changes the name" do
|
|
53
|
+
sign_in_as(<%= file_name %>)
|
|
54
|
+
patch <%= route_prefix %>_account_path, params: { <%= file_name %>: { name: "Ada Lovelace" } }
|
|
55
|
+
|
|
56
|
+
expect(<%= file_name %>.reload.name).to eq("Ada Lovelace")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "changes the email once the <%= code? ? "code" : "link" %> sent to the new one is <%= code? ? "typed" : "followed" %>", :aggregate_failures do
|
|
60
|
+
sign_in_as(<%= file_name %>)
|
|
61
|
+
change_email_to("ada@lovelace.org")
|
|
62
|
+
|
|
63
|
+
expect(ActionMailer::Base.deliveries.last.to).to eq(["ada@lovelace.org"])
|
|
64
|
+
expect(<%= file_name %>.reload.email).to eq("ada@lovelace.org")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "keeps the email when another account has the new one", :aggregate_failures do
|
|
68
|
+
<%= class_name %>.create!(email: "taken@example.com"<% if password? %>, password: "correct horse battery staple"<% end %>)
|
|
69
|
+
sign_in_as(<%= file_name %>)
|
|
70
|
+
change_email_to("taken@example.com")
|
|
71
|
+
|
|
72
|
+
expect(<%= file_name %>.reload.email).to eq("ada@example.com")
|
|
73
|
+
expect(flash[:alert]).to be_present
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "signs the other browsers out", :aggregate_failures do
|
|
77
|
+
other = <%= file_name %>.sessions.create!
|
|
78
|
+
sign_in_as(<%= file_name %>)
|
|
79
|
+
|
|
80
|
+
delete others_<%= route_prefix %>_active_sessions_path
|
|
81
|
+
|
|
82
|
+
expect(<%= class_name %>::Session.exists?(other.id)).to be(false)
|
|
83
|
+
expect(<%= file_name %>.sessions.count).to eq(1)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "deletes the account after a recent sign-in" do
|
|
87
|
+
sign_in_as(<%= file_name %>)
|
|
88
|
+
|
|
89
|
+
expect { delete <%= route_prefix %>_account_path }.to change(<%= class_name %>, :count).by(-1)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "asks to sign in again before deleting the account", :aggregate_failures do
|
|
93
|
+
sign_in_as(<%= file_name %>)
|
|
94
|
+
travel <%= class_name %>::Session::RECENT + 1.minute
|
|
95
|
+
|
|
96
|
+
expect { delete <%= route_prefix %>_account_path }.not_to change(<%= class_name %>, :count)
|
|
97
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
98
|
+
end
|
|
99
|
+
<% if password? -%>
|
|
100
|
+
|
|
101
|
+
it "sends the confirmation link again" do
|
|
102
|
+
sign_in_as(<%= file_name %>)
|
|
103
|
+
|
|
104
|
+
perform_enqueued_jobs { post <%= route_prefix %>_email_confirmation_path }
|
|
105
|
+
|
|
106
|
+
expect(ActionMailer::Base.deliveries.last.to).to eq([<%= file_name %>.email])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "changes the password after a recent sign-in, and signs the other browsers out", :aggregate_failures do
|
|
110
|
+
other = <%= file_name %>.sessions.create!
|
|
111
|
+
sign_in_as(<%= file_name %>)
|
|
112
|
+
|
|
113
|
+
patch <%= route_prefix %>_password_path, params: { <%= file_name %>: { password: "a brand new password 1!" } }
|
|
114
|
+
|
|
115
|
+
expect(<%= file_name %>.reload.authenticate("a brand new password 1!")).to be_truthy
|
|
116
|
+
expect(<%= class_name %>::Session.exists?(other.id)).to be(false)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "refuses a password breaking the rules" do
|
|
120
|
+
sign_in_as(<%= file_name %>)
|
|
121
|
+
patch <%= route_prefix %>_password_path, params: { <%= file_name %>: { password: "short" } }
|
|
122
|
+
|
|
123
|
+
expect(response).to have_http_status(:unprocessable_content)
|
|
124
|
+
end
|
|
125
|
+
<% end -%>
|
|
126
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "rails_helper"
|
|
2
|
+
|
|
3
|
+
# What any page of the site knows about who is signed in (<%= accounts_module %>::Authentication).
|
|
4
|
+
RSpec.describe ApplicationController, type: :controller do
|
|
5
|
+
controller do
|
|
6
|
+
def index
|
|
7
|
+
render plain: [current_<%= file_name %>&.email, staff_user&.email].inspect
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "knows nobody by default" do
|
|
12
|
+
get :index
|
|
13
|
+
|
|
14
|
+
expect(response.body).to eq("[nil, nil]")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "knows the signed-in <%= human_name.downcase %>" do
|
|
18
|
+
<%= file_name %>_session = <%= class_name %>.create!(email: "ada@example.com"<% if password? %>, password: "correct horse battery staple"<% end %>).sessions.create!
|
|
19
|
+
cookies.signed[<%= accounts_module %>::Authentication::COOKIE] = <%= file_name %>_session.id
|
|
20
|
+
|
|
21
|
+
get :index
|
|
22
|
+
|
|
23
|
+
expect(response.body).to eq('["ada@example.com", nil]')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "knows a staff member signed in to the admin, without signing in a <%= human_name.downcase %>" do
|
|
27
|
+
editor = users.create(role: :editor)
|
|
28
|
+
cookies.signed[:session_id] = editor.sessions.create!.id
|
|
29
|
+
|
|
30
|
+
get :index
|
|
31
|
+
|
|
32
|
+
expect(response.body).to eq("[nil, #{editor.email.inspect}]")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "ignores an admin session of a user who isn't staff anymore" do
|
|
36
|
+
reader = users.create(role: :reader)
|
|
37
|
+
cookies.signed[:session_id] = reader.sessions.create!.id
|
|
38
|
+
|
|
39
|
+
get :index
|
|
40
|
+
|
|
41
|
+
expect(response.body).to eq("[nil, nil]")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
require "rails_helper"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "<%= human_name.pluralize %>' sign-ins", type: :request do
|
|
4
|
+
include ActiveSupport::Testing::TimeHelpers
|
|
5
|
+
|
|
6
|
+
<% if code? -%>
|
|
7
|
+
def emailed_code
|
|
8
|
+
ActionMailer::Base.deliveries.last.text_part.body.to_s[/\b\d{6}\b/]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def ask_for_code(email)
|
|
12
|
+
perform_enqueued_jobs { post <%= route_prefix %>_sign_in_path, params: { email: } }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# The status and the notice, without the email it repeats
|
|
16
|
+
def answer_to_code_request(email)
|
|
17
|
+
ask_for_code(email)
|
|
18
|
+
[response.status, flash[:notice]&.sub(email, "EMAIL")]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def sign_in(email)
|
|
22
|
+
ask_for_code(email)
|
|
23
|
+
post <%= route_prefix %>_sign_in_code_path, params: { otp: emailed_code }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "renders the sign-in form" do
|
|
27
|
+
get <%= route_prefix %>_sign_in_path
|
|
28
|
+
|
|
29
|
+
expect(response).to have_http_status(:ok)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "emails a code to an email without an account, with the same answer as for an account", :aggregate_failures do
|
|
33
|
+
<%= class_name %>.create!(email: "ada@example.com")
|
|
34
|
+
|
|
35
|
+
expect(answer_to_code_request("grace@example.com")).to eq(answer_to_code_request("ada@example.com"))
|
|
36
|
+
expect(ActionMailer::Base.deliveries.flat_map(&:to)).to eq(%w[grace@example.com ada@example.com])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "refuses an invalid email" do
|
|
40
|
+
post <%= route_prefix %>_sign_in_path, params: { email: "not an email" }
|
|
41
|
+
|
|
42
|
+
expect(response).to have_http_status(:unprocessable_content)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "creates the account and signs in with the emailed code", :aggregate_failures do
|
|
46
|
+
ask_for_code("grace@example.com")
|
|
47
|
+
|
|
48
|
+
expect { post <%= route_prefix %>_sign_in_code_path, params: { otp: emailed_code } }.to change(<%= class_name %>, :count).by(1)
|
|
49
|
+
expect(response).to redirect_to(<%= route_prefix %>_account_url)
|
|
50
|
+
expect(cookies[<%= accounts_module %>::Authentication::COOKIE]).to be_present
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "signs in to the email's account", :aggregate_failures do
|
|
54
|
+
<%= file_name %> = <%= class_name %>.create!(email: "ada@example.com")
|
|
55
|
+
ask_for_code("Ada@Example.com")
|
|
56
|
+
|
|
57
|
+
expect { post <%= route_prefix %>_sign_in_code_path, params: { otp: emailed_code } }.not_to change(<%= class_name %>, :count)
|
|
58
|
+
expect(<%= file_name %>.sessions.count).to eq(1)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "refuses a wrong code", :aggregate_failures do
|
|
62
|
+
ask_for_code("ada@example.com")
|
|
63
|
+
post <%= route_prefix %>_sign_in_code_path, params: { otp: "000000" }
|
|
64
|
+
|
|
65
|
+
expect(response).to have_http_status(:unprocessable_content)
|
|
66
|
+
expect(<%= class_name %>.count).to eq(0)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "asks for the email first" do
|
|
70
|
+
get <%= route_prefix %>_sign_in_code_path
|
|
71
|
+
|
|
72
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
73
|
+
end
|
|
74
|
+
<% else -%>
|
|
75
|
+
let(:password) { "correct horse battery staple" }
|
|
76
|
+
let(:<%= file_name %>) { <%= class_name %>.create!(email: "ada@example.com", password:) }
|
|
77
|
+
|
|
78
|
+
def sign_in(email, password: self.password)
|
|
79
|
+
post <%= route_prefix %>_sign_in_path, params: { email:, password: }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def sign_up(email)
|
|
83
|
+
perform_enqueued_jobs { post <%= route_prefix %>_sign_up_path, params: { <%= file_name %>: { email:, password: } } }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "renders the sign-in and sign-up forms", :aggregate_failures do
|
|
87
|
+
get <%= route_prefix %>_sign_in_path
|
|
88
|
+
expect(response).to have_http_status(:ok)
|
|
89
|
+
|
|
90
|
+
get <%= route_prefix %>_sign_up_path
|
|
91
|
+
expect(response).to have_http_status(:ok)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "signs up and in, and emails a link to confirm the email", :aggregate_failures do
|
|
95
|
+
expect { sign_up("grace@example.com") }.to change(<%= class_name %>, :count).by(1)
|
|
96
|
+
expect(response).to redirect_to(<%= route_prefix %>_account_path)
|
|
97
|
+
expect(ActionMailer::Base.deliveries.last.to).to eq(["grace@example.com"])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "confirms the email with the emailed link", :aggregate_failures do
|
|
101
|
+
sign_up("grace@example.com")
|
|
102
|
+
link = ActionMailer::Base.deliveries.last.text_part.body.to_s[%r{https?://\S+}]
|
|
103
|
+
|
|
104
|
+
get link
|
|
105
|
+
expect(<%= class_name %>.find_by(email: "grace@example.com")).to be_confirmed
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "refuses a password breaking the rules on signing up" do
|
|
109
|
+
post <%= route_prefix %>_sign_up_path, params: { <%= file_name %>: { email: "grace@example.com", password: "short" } }
|
|
110
|
+
|
|
111
|
+
expect(response).to have_http_status(:unprocessable_content)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "signs in", :aggregate_failures do
|
|
115
|
+
sign_in(<%= file_name %>.email)
|
|
116
|
+
|
|
117
|
+
expect(response).to redirect_to(<%= route_prefix %>_account_url)
|
|
118
|
+
expect(<%= file_name %>.sessions.count).to eq(1)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "refuses a wrong password, and an unknown email, with the same answer" do
|
|
122
|
+
sign_in(<%= file_name %>.email, password: "wrong horse battery staple")
|
|
123
|
+
wrong_password = [response.status, flash[:alert]]
|
|
124
|
+
sign_in("nobody@example.com")
|
|
125
|
+
|
|
126
|
+
expect([response.status, flash[:alert]]).to eq(wrong_password)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "locks signing in after failures in a row, and emails the account", :aggregate_failures do
|
|
130
|
+
perform_enqueued_jobs { <%= class_name %>.sign_in_lockout_after.times { sign_in(<%= file_name %>.email, password: "wrong horse battery staple") } }
|
|
131
|
+
sign_in(<%= file_name %>.email)
|
|
132
|
+
|
|
133
|
+
expect(response).to have_http_status(:unprocessable_content)
|
|
134
|
+
expect(ActionMailer::Base.deliveries.last.to).to eq([<%= file_name %>.email])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
describe "password reset" do
|
|
138
|
+
def ask_for_reset(email)
|
|
139
|
+
perform_enqueued_jobs { post <%= route_prefix %>_password_reset_path, params: { email: } }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "emails a link to an account, with the same answer as for an unknown email", :aggregate_failures do
|
|
143
|
+
ask_for_reset("nobody@example.com")
|
|
144
|
+
unknown = [response.status, flash[:notice]]
|
|
145
|
+
ask_for_reset(<%= file_name %>.email)
|
|
146
|
+
|
|
147
|
+
expect([response.status, flash[:notice]]).to eq(unknown)
|
|
148
|
+
expect(ActionMailer::Base.deliveries.flat_map(&:to)).to eq([<%= file_name %>.email])
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "sets the new password, and signs every session out", :aggregate_failures do
|
|
152
|
+
<%= file_name %>.sessions.create!
|
|
153
|
+
token = <%= file_name %>.password_reset_token
|
|
154
|
+
|
|
155
|
+
patch <%= route_prefix %>_password_reset_path, params: { token:, <%= file_name %>: { password: "a brand new password 1!" } }
|
|
156
|
+
|
|
157
|
+
expect(<%= file_name %>.reload.authenticate("a brand new password 1!")).to be_truthy
|
|
158
|
+
expect(<%= file_name %>.sessions).to be_empty
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "refuses a wrong link" do
|
|
162
|
+
get edit_<%= route_prefix %>_password_reset_path(token: "wrong")
|
|
163
|
+
|
|
164
|
+
expect(response).to redirect_to(new_<%= route_prefix %>_password_reset_path)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
<% end -%>
|
|
168
|
+
|
|
169
|
+
it "goes back to the page that asked to sign in" do
|
|
170
|
+
get <%= route_prefix %>_account_path
|
|
171
|
+
sign_in(<% if code? %>"ada@example.com"<% else %><%= file_name %>.email<% end %>)
|
|
172
|
+
|
|
173
|
+
expect(response).to redirect_to(<%= route_prefix %>_account_url)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "signs out", :aggregate_failures do
|
|
177
|
+
sign_in(<% if code? %>"ada@example.com"<% else %><%= file_name %>.email<% end %>)
|
|
178
|
+
|
|
179
|
+
expect { delete <%= route_prefix %>_sign_out_path }.to change(<%= class_name %>::Session, :count).by(-1)
|
|
180
|
+
get <%= route_prefix %>_account_path
|
|
181
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "signs in again after the session's idle timeout" do
|
|
185
|
+
sign_in(<% if code? %>"ada@example.com"<% else %><%= file_name %>.email<% end %>)
|
|
186
|
+
|
|
187
|
+
travel <%= class_name %>::Session.idle_timeout + 1.minute
|
|
188
|
+
get <%= route_prefix %>_account_path
|
|
189
|
+
|
|
190
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
191
|
+
end
|
|
192
|
+
<% if audit_log? -%>
|
|
193
|
+
|
|
194
|
+
it "records the sign-in in the audit log" do
|
|
195
|
+
sign_in(<% if code? %>"ada@example.com"<% else %><%= file_name %>.email<% end %>)
|
|
196
|
+
|
|
197
|
+
expect(AuditLog.where(action: "<%= controllers_path %>/sessions#create", actor: <%= class_name %>.last)).to exist
|
|
198
|
+
end
|
|
199
|
+
<% end -%>
|
|
200
|
+
|
|
201
|
+
it "doesn't sign in to the admin" do
|
|
202
|
+
sign_in(<% if code? %>"ada@example.com"<% else %><%= file_name %>.email<% end %>)
|
|
203
|
+
|
|
204
|
+
get admin_root_path
|
|
205
|
+
expect(response).to redirect_to(new_admin_user_session_path)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
it "isn't signed in by the admin's session" do
|
|
209
|
+
editor = users.create(role: :editor)
|
|
210
|
+
post admin_user_session_path, params: { email: editor.email, password: users.password }
|
|
211
|
+
|
|
212
|
+
get <%= route_prefix %>_account_path
|
|
213
|
+
expect(response).to redirect_to(<%= route_prefix %>_sign_in_path)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
p Hello,
|
|
2
|
+
p
|
|
3
|
+
| To use this email address for your #{t("application_name")} account,
|
|
4
|
+
=< link_to "follow this link",
|
|
5
|
+
@url,
|
|
6
|
+
target: "_blank",
|
|
7
|
+
rel: "noopener"
|
|
8
|
+
| . It is valid for #{@validity}.
|
|
9
|
+
p If you didn't ask for it, ignore this email: your address won't be used.
|
|
10
|
+
p The #{t("application_name")} team
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Hello,
|
|
2
|
+
|
|
3
|
+
To use this email address for your <%%= t("application_name") %> account, follow this link. It is valid for <%%= @validity %>:
|
|
4
|
+
<%%= @url %>
|
|
5
|
+
|
|
6
|
+
If you didn't ask for it, ignore this email: your address won't be used.
|
|
7
|
+
|
|
8
|
+
The <%%= t("application_name") %> team
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
p Bonjour,
|
|
2
|
+
p
|
|
3
|
+
| Pour utiliser cette adresse e-mail pour votre compte
|
|
4
|
+
#{t("application_name")},
|
|
5
|
+
=< link_to "suivez ce lien",
|
|
6
|
+
@url,
|
|
7
|
+
target: "_blank",
|
|
8
|
+
rel: "noopener"
|
|
9
|
+
| . Il est valable #{@validity}.
|
|
10
|
+
p
|
|
11
|
+
| Si vous ne l'avez pas demandé, ignorez cet e-mail : votre adresse ne
|
|
12
|
+
sera pas utilisée.
|
|
13
|
+
p L'équipe #{t("application_name")}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Bonjour,
|
|
2
|
+
|
|
3
|
+
Pour utiliser cette adresse e-mail pour votre compte <%%= t("application_name") %>, suivez ce lien. Il est valable <%%= @validity %> :
|
|
4
|
+
<%%= @url %>
|
|
5
|
+
|
|
6
|
+
Si vous ne l'avez pas demandé, ignorez cet e-mail : votre adresse ne sera pas utilisée.
|
|
7
|
+
|
|
8
|
+
L'équipe <%%= t("application_name") %>
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.html.slim.tt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
p Hello,
|
|
2
|
+
p
|
|
3
|
+
| Here is your code to confirm this email address for your
|
|
4
|
+
#{t("application_name")} account:
|
|
5
|
+
p
|
|
6
|
+
strong(style="font-size: 28px; letter-spacing: 4px;") = @code
|
|
7
|
+
p It is valid for #{@validity}.
|
|
8
|
+
p If you didn't ask for it, ignore this email: your address won't be used.
|
|
9
|
+
p The #{t("application_name")} team
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.en.text.erb.tt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Hello,
|
|
2
|
+
|
|
3
|
+
Here is your code to confirm this email address for your <%%= t("application_name") %> account:
|
|
4
|
+
|
|
5
|
+
<%%= @code %>
|
|
6
|
+
|
|
7
|
+
It is valid for <%%= @validity %>.
|
|
8
|
+
|
|
9
|
+
If you didn't ask for it, ignore this email: your address won't be used.
|
|
10
|
+
|
|
11
|
+
The <%%= t("application_name") %> team
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.html.slim.tt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
p Bonjour,
|
|
2
|
+
p
|
|
3
|
+
| Voici votre code pour confirmer cette adresse e-mail pour votre compte
|
|
4
|
+
#{t("application_name")} :
|
|
5
|
+
p
|
|
6
|
+
strong(style="font-size: 28px; letter-spacing: 4px;") = @code
|
|
7
|
+
p Il est valable #{@validity}.
|
|
8
|
+
p
|
|
9
|
+
| Si vous ne l'avez pas demandé, ignorez cet e-mail : votre adresse ne
|
|
10
|
+
sera pas utilisée.
|
|
11
|
+
p L'équipe #{t("application_name")}
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_change_code.fr.text.erb.tt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Bonjour,
|
|
2
|
+
|
|
3
|
+
Voici votre code pour confirmer cette adresse e-mail pour votre compte <%%= t("application_name") %> :
|
|
4
|
+
|
|
5
|
+
<%%= @code %>
|
|
6
|
+
|
|
7
|
+
Il est valable <%%= @validity %>.
|
|
8
|
+
|
|
9
|
+
Si vous ne l'avez pas demandé, ignorez cet e-mail : votre adresse ne sera pas utilisée.
|
|
10
|
+
|
|
11
|
+
L'équipe <%%= t("application_name") %>
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.en.html.slim.tt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
p Hello,
|
|
2
|
+
p
|
|
3
|
+
| Welcome to #{t("application_name")}! Confirm your email address
|
|
4
|
+
=< link_to "with this link",
|
|
5
|
+
@url,
|
|
6
|
+
target: "_blank",
|
|
7
|
+
rel: "noopener"
|
|
8
|
+
| , valid for #{@validity}.
|
|
9
|
+
p If you didn't create this account, ignore this email.
|
|
10
|
+
p The #{t("application_name")} team
|
data/lib/generators/trek/templates/public_accounts/views/mailer/email_confirmation.fr.html.slim.tt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
p Bonjour,
|
|
2
|
+
p
|
|
3
|
+
| Bienvenue sur #{t("application_name")} ! Confirmez votre adresse e-mail
|
|
4
|
+
=< link_to "avec ce lien",
|
|
5
|
+
@url,
|
|
6
|
+
target: "_blank",
|
|
7
|
+
rel: "noopener"
|
|
8
|
+
| , valable #{@validity}.
|
|
9
|
+
p Si vous n'avez pas créé ce compte, ignorez cet e-mail.
|
|
10
|
+
p L'équipe #{t("application_name")}
|
data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.en.html.slim.tt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
p Hello,
|
|
2
|
+
p
|
|
3
|
+
| To choose a new password for your #{t("application_name")} account,
|
|
4
|
+
=< link_to "follow this link",
|
|
5
|
+
@url,
|
|
6
|
+
target: "_blank",
|
|
7
|
+
rel: "noopener"
|
|
8
|
+
| . It is valid for #{@validity}, once.
|
|
9
|
+
p If you didn't ask for it, ignore this email: your password stays the same.
|
|
10
|
+
p The #{t("application_name")} team
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Hello,
|
|
2
|
+
|
|
3
|
+
To choose a new password for your <%%= t("application_name") %> account, follow this link. It is valid for <%%= @validity %>, once:
|
|
4
|
+
<%%= @url %>
|
|
5
|
+
|
|
6
|
+
If you didn't ask for it, ignore this email: your password stays the same.
|
|
7
|
+
|
|
8
|
+
The <%%= t("application_name") %> team
|
data/lib/generators/trek/templates/public_accounts/views/mailer/password_reset.fr.html.slim.tt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
p Bonjour,
|
|
2
|
+
p
|
|
3
|
+
| Pour choisir un nouveau mot de passe pour votre compte
|
|
4
|
+
#{t("application_name")},
|
|
5
|
+
=< link_to "suivez ce lien",
|
|
6
|
+
@url,
|
|
7
|
+
target: "_blank",
|
|
8
|
+
rel: "noopener"
|
|
9
|
+
| . Il est valable #{@validity}, une seule fois.
|
|
10
|
+
p
|
|
11
|
+
| Si vous ne l'avez pas demandé, ignorez cet e-mail : votre mot de passe
|
|
12
|
+
reste le même.
|
|
13
|
+
p L'équipe #{t("application_name")}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Bonjour,
|
|
2
|
+
|
|
3
|
+
Pour choisir un nouveau mot de passe pour votre compte <%%= t("application_name") %>, suivez ce lien. Il est valable <%%= @validity %>, une seule fois :
|
|
4
|
+
<%%= @url %>
|
|
5
|
+
|
|
6
|
+
Si vous ne l'avez pas demandé, ignorez cet e-mail : votre mot de passe reste le même.
|
|
7
|
+
|
|
8
|
+
L'équipe <%%= t("application_name") %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
p Hello,
|
|
2
|
+
p Here is your code to sign in to #{t("application_name")}:
|
|
3
|
+
p
|
|
4
|
+
strong(style="font-size: 28px; letter-spacing: 4px;") = @code
|
|
5
|
+
p It is valid for #{@validity}, for this sign-in only.
|
|
6
|
+
p
|
|
7
|
+
| If you didn't ask for it, ignore this email: nobody can sign in without
|
|
8
|
+
the code.
|
|
9
|
+
p The #{t("application_name")} team
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Hello,
|
|
2
|
+
|
|
3
|
+
Here is your code to sign in to <%%= t("application_name") %>:
|
|
4
|
+
|
|
5
|
+
<%%= @code %>
|
|
6
|
+
|
|
7
|
+
It is valid for <%%= @validity %>, for this sign-in only.
|
|
8
|
+
|
|
9
|
+
If you didn't ask for it, ignore this email: nobody can sign in without the code.
|
|
10
|
+
|
|
11
|
+
The <%%= t("application_name") %> team
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
p Bonjour,
|
|
2
|
+
p Voici votre code pour vous connecter à #{t("application_name")} :
|
|
3
|
+
p
|
|
4
|
+
strong(style="font-size: 28px; letter-spacing: 4px;") = @code
|
|
5
|
+
p Il est valable #{@validity}, pour cette connexion uniquement.
|
|
6
|
+
p
|
|
7
|
+
| Si vous ne l'avez pas demandé, ignorez cet e-mail : personne ne peut se
|
|
8
|
+
connecter sans le code.
|
|
9
|
+
p L'équipe #{t("application_name")}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Bonjour,
|
|
2
|
+
|
|
3
|
+
Voici votre code pour vous connecter à <%%= t("application_name") %> :
|
|
4
|
+
|
|
5
|
+
<%%= @code %>
|
|
6
|
+
|
|
7
|
+
Il est valable <%%= @validity %>, pour cette connexion uniquement.
|
|
8
|
+
|
|
9
|
+
Si vous ne l'avez pas demandé, ignorez cet e-mail : personne ne peut se connecter sans le code.
|
|
10
|
+
|
|
11
|
+
L'équipe <%%= t("application_name") %>
|
data/lib/generators/trek/templates/public_accounts/views/mailer/sign_in_locked.en.html.slim.tt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
p Hello #{@<%= file_name %>},
|
|
2
|
+
p
|
|
3
|
+
| Several attempts in a row to sign in to #{t("application_name")} with
|
|
4
|
+
your email failed, with a wrong password. To keep your account safe,
|
|
5
|
+
signing in is paused for a few minutes, a little longer after each new
|
|
6
|
+
failure.
|
|
7
|
+
<% unless web? -%>
|
|
8
|
+
p
|
|
9
|
+
| If it was you, wait a few minutes before trying again, or reset your
|
|
10
|
+
password from the app.
|
|
11
|
+
<% else -%>
|
|
12
|
+
p
|
|
13
|
+
| If it was you, wait a few minutes before trying again, or
|
|
14
|
+
=< link_to "choose a new password",
|
|
15
|
+
@reset_url,
|
|
16
|
+
target: "_blank",
|
|
17
|
+
rel: "noopener"
|
|
18
|
+
| .
|
|
19
|
+
<% end -%>
|
|
20
|
+
p
|
|
21
|
+
| If it wasn't you, someone may be trying to guess your password: if it's
|
|
22
|
+
short or you use it elsewhere, choose a new one.
|
|
23
|
+
p The #{t("application_name")} team
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Hello <%%= @<%= file_name %> %>,
|
|
2
|
+
|
|
3
|
+
Several attempts in a row to sign in to <%%= t("application_name") %> with your email failed, with a wrong password. To keep your account safe, signing in is paused for a few minutes, a little longer after each new failure.
|
|
4
|
+
|
|
5
|
+
<% unless web? -%>
|
|
6
|
+
If it was you, wait a few minutes before trying again, or reset your password from the app.
|
|
7
|
+
<% else -%>
|
|
8
|
+
If it was you, wait a few minutes before trying again, or choose a new password:
|
|
9
|
+
<%%= @reset_url %>
|
|
10
|
+
<% end -%>
|
|
11
|
+
|
|
12
|
+
If it wasn't you, someone may be trying to guess your password: if it's short or you use it elsewhere, choose a new one.
|
|
13
|
+
|
|
14
|
+
The <%%= t("application_name") %> team
|