Fix #4571: Show banner when email verification is required.

* Show a banner if the user is restricted because they signed up from a
  proxy or VPN.

* Add an option to resend the confirmation email if your account has an
  unverified email address.
This commit is contained in:
evazion
2020-08-02 16:32:49 -05:00
parent a8577b2b94
commit baf0cf87af
11 changed files with 173 additions and 22 deletions

View File

@@ -21,7 +21,7 @@ class EmailsController < ApplicationController
end
if @user.errors.none?
flash[:notice] = "Email updated"
flash[:notice] = "Email updated. Check your email to confirm your new address"
UserMailer.email_change_confirmation(@user).deliver_later
respond_with(@user, location: settings_url)
else
@@ -31,10 +31,27 @@ class EmailsController < ApplicationController
end
def verify
@email_address = authorize EmailAddress.find_by_user_id!(params[:user_id])
@email_address.update!(is_verified: true)
@user = User.find(params[:user_id])
@email_address = @user.email_address
flash[:notice] = "Email address verified"
redirect_to @email_address.user
if @email_address.blank?
redirect_to edit_user_email_path(@user)
elsif params[:email_verification_key].present?
authorize @email_address
@email_address.update!(is_verified: true)
flash[:notice] = "Email address verified"
redirect_to @email_address.user
else
authorize @email_address
respond_with(@user)
end
end
def send_confirmation
@user = authorize User.find(params[:user_id]), policy_class: EmailAddressPolicy
UserMailer.welcome_user(@user).deliver_later
flash[:notice] = "Confirmation email sent to #{@user.email_address.address}. Check your email to confirm your address"
redirect_to @user
end
end

View File

@@ -15,6 +15,12 @@ $(function() {
e.preventDefault();
});
$("#hide-verify-account-notice").on("click.danbooru", function(e) {
$("#verify-account-notice").hide();
Cookie.put('hide_verify_account_notice', '1', 3);
e.preventDefault();
});
$("#close-notice-link").on("click.danbooru", function(e) {
$('#notice').fadeOut("fast");
e.preventDefault();

View File

@@ -267,6 +267,10 @@ class User < ApplicationRecord
name.match?(/\Auser_[0-9]+~*\z/)
end
def is_restricted?
requires_verification? && !is_verified?
end
def is_anonymous?
level == Levels::ANONYMOUS
end

View File

@@ -9,6 +9,15 @@ class EmailAddressPolicy < ApplicationPolicy
end
def verify?
record.valid_key?(request.params[:email_verification_key])
if request.params[:email_verification_key].present?
record.valid_key?(request.params[:email_verification_key])
else
record.user_id == user.id
end
end
def send_confirmation?
# XXX record is a user, not the email address.
record.id == user.id
end
end

View File

@@ -1,14 +1,26 @@
<% page_title "Change Email" %>
<div id="c-emails">
<div id="a-edit">
<h1>Change Email</h1>
<div id="a-edit" class="fixed-width-container">
<% if @user.email_address.present? %>
<% page_title "Change Email" %>
<h1>Change Email</h1>
<p>You must confirm your password in order to change your email address.</p>
<p>Your current email address is <strong><%= @user.email_address.address %></strong>. You must re-enter your password in order to update your email address.</p>
<% else %>
<% page_title "Add Email" %>
<h1>Add Email</h1>
<p>Add a new email address below. You must re-enter your password in order to update your email address.</p>
<% end %>
<% if @user.is_restricted? %>
<p>Your account is restricted because you signed up from a VPN or proxy.
You can still use the site, but you won't be able to leave comments, edit
tags, or upload posts until you add a verified email address to your account.</p>
<% end %>
<%= edit_form_for(@user, url: user_email_path(@user)) do |f| %>
<%= f.input :email, as: :email, label: "New Email", input_html: { value: "" } %>
<%= f.input :password %>
<%= f.input :email, as: :email, input_html: { value: "" } %>
<%= f.submit "Save" %>
<% end %>
</div>

View File

@@ -0,0 +1,20 @@
<% page_title "Verify account" %>
<div id="c-emails">
<div id="a-verify" class="fixed-width-container">
<h1>Verify account</h1>
<% if @user.is_restricted? %>
<p>Your account is restricted because you signed up from a VPN or proxy.
You can still use the site, but you won't be able to leave comments, edit
tags, or upload posts until you verify your account.</p>
<% end %>
<p>Click below to send an email to <strong><%= @email_address.address %></strong>
to verify your account.</p>
<%= edit_form_for(@user, method: :post, url: send_confirmation_user_email_path(@user)) do |f| %>
<%= f.submit "Send confirmation email" %>
<% end %>
</div>
</div>

View File

@@ -68,6 +68,8 @@
</header>
<div id="page">
<%= render "users/verification_notice" %>
<% if !CurrentUser.is_anonymous? && !CurrentUser.is_gold? && cookies[:hide_upgrade_account_notice].blank? && params[:action] != "upgrade_information" %>
<%= render "users/upgrade_notice" %>
<% end %>

View File

@@ -0,0 +1,10 @@
<% if CurrentUser.user.is_restricted? && (params[:controller] == "users" || cookies[:hide_verify_account_notice].blank?) %>
<div class="notice notice-info notice-large" id="verify-account-notice">
<h2>Your account is restricted.</h2>
<div>
You must verify your account because you signed up from a proxy or a VPN.
<%= link_to "Verify your account now", verify_user_email_path(CurrentUser.user) %>.
</div>
<div><%= link_to "Close this", "#", id: "hide-verify-account-notice" %></div>
</div>
<% end %>

View File

@@ -27,14 +27,14 @@
<p>
<% if @user.email_address.present? %>
<%= @user.email_address.address %>
<% if !@user.email_address.is_verified %>
<em>(unverified)</em>
<% end %>
<% else %>
<em>blank</em>
<% end %>
- <%= link_to "Change your email", edit_user_email_path(@user) %>
(<%= link_to "Change email", edit_user_email_path(@user) %>
<% if !@user.email_address.is_verified %>
| <%= link_to "Verify email", verify_user_email_path(@user) %>
<% end %>)
<% else %>
<%= link_to "Add email", edit_user_email_path(@user) %>
<% end %>
</p>
</div>

View File

@@ -246,6 +246,7 @@ Rails.application.routes.draw do
resources :favorite_groups, controller: "favorite_groups", only: [:index], as: "favorite_groups"
resource :email, only: [:show, :edit, :update] do
get :verify
post :send_confirmation
end
resource :password, only: [:edit, :update]
resource :api_key, :only => [:show, :view, :update, :destroy], :controller => "maintenance/user/api_keys" do

View File

@@ -7,6 +7,7 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
setup do
@user = create(:user, email_address: build(:email_address, { address: "bob@ogres.net", is_verified: false }))
@other_user = create(:user, email_address: build(:email_address, { address: "alice@ogres.net", is_verified: false }))
@restricted_user = create(:user, requires_verification: true, is_verified: false)
end
context "#show" do
@@ -22,9 +23,36 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
end
context "#edit" do
should "render" do
get_auth edit_user_email_path(@user), @user
assert_response :success
context "for a user with an email address" do
should "render" do
get_auth edit_user_email_path(@user), @user
assert_equal true, @user.email_address.present?
assert_response :success
end
end
context "for a user without an email address" do
should "render" do
@user.email_address.destroy!
get_auth edit_user_email_path(@user), @user
assert_equal false, @user.email_address.present?
assert_response :success
end
end
context "for a restricted user" do
should "render" do
get_auth edit_user_email_path(@restricted_user), @restricted_user
assert_response :success
end
end
context "for an unauthorized user" do
should "render" do
get_auth edit_user_email_path(@user), @other_user
assert_response 403
end
end
end
@@ -109,6 +137,48 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
assert_equal(false, @user.is_verified)
end
end
context "for a user without an email address" do
should "redirect to the add email page" do
@user.email_address.destroy!
get_auth verify_user_email_path(@user), @user
assert_redirected_to edit_user_email_path(@user)
end
end
context "for a user with an unverified email address" do
should "show the resend confirmation email page" do
get_auth verify_user_email_path(@user), @user
assert_response :success
end
end
context "for an unauthorized user" do
should "fail" do
get_auth verify_user_email_path(@user), @other_user
assert_response 403
end
end
end
context "#send_confirmation" do
context "for an authorized user" do
should "resend the confirmation email" do
post_auth send_confirmation_user_email_path(@user), @user
assert_redirected_to @user
assert_enqueued_emails 1
end
end
context "for an unauthorized user" do
should "fail" do
post_auth send_confirmation_user_email_path(@user), @other_user
assert_response 403
assert_no_enqueued_emails
end
end
end
end
end