Skip to content

Commit 00db048

Browse files
authored
Merge pull request #1968 from basecamp/flavorjones/only-email-confirmed-users
Mark users as "verified" and only send notifications to verified users
2 parents 345f457 + fc8ef33 commit 00db048

File tree

22 files changed

+268
-27
lines changed

22 files changed

+268
-27
lines changed

app/controllers/join_codes_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def create
1818
if identity == Current.identity && user.setup?
1919
redirect_to landing_url(script_name: @join_code.account.slug)
2020
elsif identity == Current.identity
21-
redirect_to new_users_join_url(script_name: @join_code.account.slug)
21+
redirect_to new_users_verification_url(script_name: @join_code.account.slug)
2222
else
2323
logout_and_send_new_magic_link(identity)
2424
redirect_to session_magic_link_url(script_name: nil)
@@ -44,6 +44,6 @@ def logout_and_send_new_magic_link(identity)
4444
magic_link = identity.send_magic_link
4545
serve_development_magic_link(magic_link)
4646

47-
session[:return_to_after_authenticating] = new_users_join_url(script_name: @join_code.account.slug)
47+
session[:return_to_after_authenticating] = new_users_verification_url(script_name: @join_code.account.slug)
4848
end
4949
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Users::VerificationsController < ApplicationController
2+
layout "public"
3+
4+
def new
5+
end
6+
7+
def create
8+
Current.user.verify
9+
redirect_to new_users_join_path
10+
end
11+
end

app/javascript/controllers/magic_link_controller.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ import { onNextEventLoopTick } from "helpers/timing_helpers"
44
export default class extends Controller {
55
static targets = [ "input" ]
66

7+
submitOnEnter(event) {
8+
event.preventDefault()
9+
this.submit()
10+
}
11+
12+
submitOnPaste() {
13+
onNextEventLoopTick(() => this.submit())
14+
}
15+
716
submit() {
8-
onNextEventLoopTick(() => {
9-
if (!this.inputTarget.disabled) {
10-
this.element.submit()
11-
this.inputTarget.disabled = true
12-
}
13-
})
17+
if (this.inputTarget.disabled) return
18+
this.element.submit()
19+
this.inputTarget.disabled = true
1420
}
1521
}

app/models/account.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class << self
2121
def create_with_owner(account:, owner:)
2222
create!(**account).tap do |account|
2323
account.users.create!(role: :system, name: "System")
24-
account.users.create!(**owner.reverse_merge(role: "owner"))
24+
account.users.create!(**owner.reverse_merge(role: "owner", verified_at: Time.current))
2525
end
2626
end
2727
end

app/models/user.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ def setup?
2828
name != identity.email_address
2929
end
3030

31+
def verified?
32+
verified_at.present?
33+
end
34+
35+
def verify
36+
update!(verified_at: Time.current) unless verified?
37+
end
38+
3139
private
3240
def close_remote_connections
3341
ActionCable.server.remote_connections.where(current_user: self).disconnect(reconnect: false)

app/models/user/settings.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def bundle_aggregation_period
2121
end
2222

2323
def bundling_emails?
24-
!bundle_email_never? && !user.system? && user.active?
24+
!bundle_email_never? && !user.system? && user.active? && user.verified?
2525
end
2626

2727
def timezone

app/views/sessions/magic_links/show.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<%= form.text_field :code, required: true, class: "input center txt-align-enter txt-large",
1111
autofocus: true, autocorrect: "off", autocapitalize: "off", spellcheck: "false", "data-1p-ignore": true,
1212
autocomplete: "one-time-code", maxlength: "6", placeholder: "••••••", value: params[:code],
13-
data: { magic_link_target: "input", action: "keydown.enter->magic-link#submit paste->magic-link#submit" } %>
13+
data: { magic_link_target: "input", action: "keydown.enter->magic-link#submitOnEnter paste->magic-link#submitOnPaste" } %>
1414
<% end %>
1515

1616
<p class="txt-small">The code you receive will work for <%= distance_of_time_in_words(MagicLink::EXPIRATION_TIME) %>.</p>

app/views/users/show.html.erb

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,25 @@
1818
<div class="flex flex-column gap-half margin-block-end">
1919
<h1 class="txt-x-large margin-none"><%= @user.name %></h1>
2020
<div class="txt-medium">
21-
<% if @user.active? %>
22-
<%= mail_to @user.identity.email_address %>
23-
<% else %>
21+
<% if !@user.active? %>
2422
<%= @user.name %> is no longer on this account
23+
<% elsif !@user.verified? %>
24+
Unverified
25+
<div class="txt-small txt-tinted">A sign-in code has been sent to this email address, but the user has not yet logged in to confirm their identity.</div>
26+
<% else %>
27+
<%= mail_to @user.identity.email_address %>
2528
<% end %>
2629
</div>
2730
</div>
2831

29-
<div class="flex-inline center justify-center flex-wrap gap">
30-
<%= link_to "Which cards are assigned to #{me_or_you}?",
31-
cards_path(assignee_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %>
32-
<%= link_to "Which cards were added by #{me_or_you}?",
33-
cards_path(creator_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %>
34-
</div>
32+
<% if @user.verified? %>
33+
<div class="flex-inline center justify-center flex-wrap gap">
34+
<%= link_to "Which cards are assigned to #{me_or_you}?",
35+
cards_path(assignee_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %>
36+
<%= link_to "Which cards were added by #{me_or_you}?",
37+
cards_path(creator_ids: [ @user.id ], sorted_by: "newest"), class: "btn", data: { turbo_frame: "_top" } %>
38+
</div>
39+
<% end %>
3540
</div>
3641
</section>
3742

@@ -48,4 +53,6 @@
4853
<% end %>
4954
</div>
5055

51-
<%= turbo_frame_tag "user_events", src: user_events_path(@user) %>
56+
<% if @user.verified? %>
57+
<%= turbo_frame_tag "user_events", src: user_events_path(@user) %>
58+
<% end %>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%= auto_submit_form_with url: users_verifications_path, method: :post %>

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138

139139
namespace :users do
140140
resources :joins
141+
resources :verifications, only: %i[ new create ]
141142
end
142143

143144
resource :session do

0 commit comments

Comments
 (0)